From 1042eeeeda1fc50dfa9a0a173933ba14a46d156a Mon Sep 17 00:00:00 2001 From: "Michael S. Fischer" Date: Mon, 16 Dec 2019 15:01:33 -0800 Subject: [PATCH] Add AWS Access Key ID to log Add the AWS Access Key ID to the STS response log. This should make it easier to audit the true identity of the user or process that authenticated to the cluster. --- pkg/server/server.go | 11 ++++++----- pkg/token/token.go | 15 ++++++++++++--- pkg/token/token_test.go | 8 ++++++-- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/pkg/server/server.go b/pkg/server/server.go index 1c125a50b..2db531c6a 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -1,5 +1,5 @@ /* -Copyright 2017 by the contributors. +Copyright 2017-2020 by the contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -294,10 +294,11 @@ func (h *handler) authenticateEndpoint(w http.ResponseWriter, req *http.Request) } log.WithFields(logrus.Fields{ - "arn": identity.ARN, - "accountid": identity.AccountID, - "userid": identity.UserID, - "session": identity.SessionName, + "accesskeyid": identity.AccessKeyID, + "arn": identity.ARN, + "accountid": identity.AccountID, + "userid": identity.UserID, + "session": identity.SessionName, }).Info("STS response") // look up the ARN in each of our mappings to fill in the username and groups diff --git a/pkg/token/token.go b/pkg/token/token.go index dba5e8bda..00970a991 100644 --- a/pkg/token/token.go +++ b/pkg/token/token.go @@ -1,5 +1,5 @@ /* -Copyright 2017 by the contributors. +Copyright 2017-2020 by the contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -66,6 +66,11 @@ type Identity struct { // users or other roles are allowed to assume the role, they can provide // (nearly) arbitrary strings here. SessionName string + + // The AWS Access Key ID used to authenticate the request. This can be used + // in conjuction with CloudTrail to determine the identity of the individual + // if the individual assumed an IAM role before making the request. + AccessKeyID string } const ( @@ -431,6 +436,9 @@ func (v tokenVerifier) Verify(token string) (*Identity, error) { return nil, FormatError{"X-Amz-Date parameter must be present in pre-signed URL"} } + // Obtain AWS Access Key ID from supplied credentials + accessKeyID := strings.Split(queryParamsLower.Get("x-amz-credential"), "/")[0] + dateParam, err := time.Parse(dateHeaderFormat, date) if err != nil { return nil, FormatError{fmt.Sprintf("error parsing X-Amz-Date parameter %s into format %s: %s", date, dateHeaderFormat, err.Error())} @@ -473,8 +481,9 @@ func (v tokenVerifier) Verify(token string) (*Identity, error) { // parse the response into an Identity id := &Identity{ - ARN: callerIdentity.GetCallerIdentityResponse.GetCallerIdentityResult.Arn, - AccountID: callerIdentity.GetCallerIdentityResponse.GetCallerIdentityResult.Account, + ARN: callerIdentity.GetCallerIdentityResponse.GetCallerIdentityResult.Arn, + AccountID: callerIdentity.GetCallerIdentityResponse.GetCallerIdentityResult.Account, + AccessKeyID: accessKeyID, } id.CanonicalARN, err = arn.Canonicalize(id.ARN) if err != nil { diff --git a/pkg/token/token_test.go b/pkg/token/token_test.go index 1a6f30618..de6359ca2 100644 --- a/pkg/token/token_test.go +++ b/pkg/token/token_test.go @@ -48,8 +48,8 @@ func assertSTSError(t *testing.T, err error) { var ( now = time.Now() timeStr = now.UTC().Format("20060102T150405Z") + validURL = fmt.Sprintf("https://sts.amazonaws.com/?action=GetCallerIdentity&X-Amz-Credential=ASIABCDEFGHIJKLMNOPQ%%2F20191216%%2Fus-west-2%%2Fs3%%2Faws4_request&x-amz-signedheaders=x-k8s-aws-id&x-amz-expires=60&x-amz-date=%s", timeStr) validToken = toToken(validURL) - validURL = fmt.Sprintf("https://sts.amazonaws.com/?action=GetCallerIdentity&x-amz-signedheaders=x-k8s-aws-id&x-amz-expires=60&x-amz-date=%s", timeStr) ) func toToken(url string) string { @@ -209,15 +209,19 @@ func TestVerifyNoSession(t *testing.T) { arn := "arn:aws:iam::123456789012:user/Alice" account := "123456789012" userID := "Alice" + accessKeyID := "ASIABCDEFGHIJKLMNOPQ" identity, err := newVerifier(200, jsonResponse(arn, account, userID), nil).Verify(validToken) if err != nil { t.Errorf("expected error to be nil was %q", err) } + if identity.AccessKeyID != accessKeyID { + t.Errorf("expected AccessKeyID to be %q but was %q", accessKeyID, identity.AccessKeyID) + } if identity.ARN != arn { t.Errorf("expected ARN to be %q but was %q", arn, identity.ARN) } if identity.CanonicalARN != arn { - t.Errorf("expected CannonicalARN to be %q but was %q", arn, identity.CanonicalARN) + t.Errorf("expected CanonicalARN to be %q but was %q", arn, identity.CanonicalARN) } if identity.UserID != userID { t.Errorf("expected Username to be %q but was %q", userID, identity.UserID)