| 133 | } |
| 134 | |
| 135 | func (c *Credentials) Validate() error { |
| 136 | if c == nil { |
| 137 | return fmt.Errorf("%w: nil credentials", backend.ErrValidation) |
| 138 | } |
| 139 | if c.AccessPointARN == "" { |
| 140 | return fmt.Errorf("%w: missing access_point_arn", backend.ErrValidation) |
| 141 | } |
| 142 | if !strings.HasPrefix(c.AccessPointARN, "arn:aws:s3:") || !strings.Contains(c.AccessPointARN, ":accesspoint/") { |
| 143 | return fmt.Errorf("%w: access_point_arn %q is not an S3 access point ARN", backend.ErrValidation, c.AccessPointARN) |
| 144 | } |
| 145 | if c.Region == "" { |
| 146 | return fmt.Errorf("%w: missing region", backend.ErrValidation) |
| 147 | } |
| 148 | if !devModeEnabled() { |
| 149 | if c.BaseRoleARN == "" { |
| 150 | return fmt.Errorf("%w: missing base_role_arn", backend.ErrValidation) |
| 151 | } |
| 152 | if !strings.HasPrefix(c.BaseRoleARN, "arn:aws:iam::") { |
| 153 | return fmt.Errorf("%w: base_role_arn %q is not a valid IAM role ARN", backend.ErrValidation, c.BaseRoleARN) |
| 154 | } |
| 155 | } |
| 156 | // SessionPolicyARN is optional. When set it must be a syntactically |
| 157 | // valid IAM managed policy ARN — anything else (an S3 ARN, a role |
| 158 | // ARN, a policy ARN with no name, a role ARN that happens to embed |
| 159 | // ":policy/" in its path) would be silently rejected by STS at |
| 160 | // request time, surfacing as opaque errors deep in the upload path. |
| 161 | // Fail loudly here instead. |
| 162 | if c.SessionPolicyARN != "" { |
| 163 | a, err := arn.Parse(c.SessionPolicyARN) |
| 164 | if err != nil || |
| 165 | a.Service != "iam" || |
| 166 | !strings.HasPrefix(a.Resource, "policy/") || |
| 167 | a.Resource == "policy/" { |
| 168 | return fmt.Errorf("%w: session_policy_arn %q is not a valid IAM managed policy ARN", backend.ErrValidation, c.SessionPolicyARN) |
| 169 | } |
| 170 | } |
| 171 | return nil |
| 172 | } |
| 173 | |
| 174 | // BackendProvider implements backend.Provider for the access-point-backed |
| 175 | // managed CAS. Construction takes only the credentials reader; everything |