Skip to content

Commit

Permalink
plugins: Surface AWS authentication error details
Browse files Browse the repository at this point in the history
OPA supports multiple AWS authentication methods. Currently
on an unsuccessful authentication, OPA logs the error at the debug
level. It would be helpful especially in a prod env to surface these
errors via the Status API to assist with debugging issues. This change
attempts to achieve that.

Fixes: #6232

Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
  • Loading branch information
ashutosh-narkar committed Sep 25, 2023
1 parent 276702f commit 919b290
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 5 deletions.
39 changes: 38 additions & 1 deletion plugins/rest/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,43 @@ func (acs *awsCredentialServiceChain) addService(service awsCredentialService) {
acs.awsCredentialServices = append(acs.awsCredentialServices, service)
}

type awsCredentialCheckErrors []*awsCredentialCheckError

func (e awsCredentialCheckErrors) Error() string {

if len(e) == 0 {
return "no error(s)"
}

if len(e) == 1 {
return fmt.Sprintf("1 error occurred: %v", e[0].Error())
}

s := make([]string, len(e))
for i, err := range e {
s[i] = err.Error()
}

return fmt.Sprintf("%d errors occurred:\n%s", len(e), strings.Join(s, "\n"))
}

type awsCredentialCheckError struct {
message string
}

func newAWSCredentialError(message string) *awsCredentialCheckError {
return &awsCredentialCheckError{
message: message,
}
}

func (e *awsCredentialCheckError) Error() string {
return e.message
}

func (acs *awsCredentialServiceChain) credentials(ctx context.Context) (aws.Credentials, error) {
var errs awsCredentialCheckErrors

for _, service := range acs.awsCredentialServices {
credential, err := service.credentials(ctx)
if err != nil {
Expand All @@ -731,14 +767,15 @@ func (acs *awsCredentialServiceChain) credentials(ctx context.Context) (aws.Cred
return aws.Credentials{}, err
}

errs = append(errs, newAWSCredentialError(err.Error()))
continue
}

acs.logger.Debug("awsSigningAuthPlugin:%T successful", service)
return credential, nil
}

return aws.Credentials{}, errors.New("all AWS credential providers failed")
return aws.Credentials{}, fmt.Errorf("all AWS credential providers failed: %v", errs)
}

func (ap *awsSigningAuthPlugin) awsCredentialService() awsCredentialService {
Expand Down
19 changes: 15 additions & 4 deletions plugins/rest/rest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1789,6 +1789,7 @@ func TestAWSCredentialServiceChain(t *testing.T) {
input string
wantErr bool
env map[string]string
errMsg string
}{
{
name: "Fallback to Environment Credential",
Expand Down Expand Up @@ -1826,6 +1827,7 @@ func TestAWSCredentialServiceChain(t *testing.T) {
}
}`,
wantErr: true,
errMsg: "all AWS credential providers failed: 4 errors occurred",
env: map[string]string{},
},
}
Expand Down Expand Up @@ -1859,10 +1861,19 @@ func TestAWSCredentialServiceChain(t *testing.T) {

awsPlugin.logger = client.logger
err = awsPlugin.Prepare(req)
if err != nil && !tc.wantErr {
t.Fatalf("Unexpected error: %v", err)
} else if err == nil && tc.wantErr {
t.Fatalf("Expected error for input %v", tc.input)

if tc.wantErr {
if err == nil {
t.Fatalf("Expected error for input %v", tc.input)
}

if !strings.Contains(err.Error(), tc.errMsg) {
t.Fatalf("Expected error message %v but got %v", tc.errMsg, err.Error())
}
} else {
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
}
})
}
Expand Down

0 comments on commit 919b290

Please sign in to comment.