From 918e68e82bb86b9923a49a182bf4a5c6f514f90b Mon Sep 17 00:00:00 2001 From: Roman Iuvshyn Date: Wed, 6 May 2020 18:07:19 +0300 Subject: [PATCH 1/6] Adds optional validate_iss_claim config param to allow skip iss validation --- go.mod | 2 ++ go.sum | 9 +++++++++ path_config.go | 13 +++++++++++++ path_config_test.go | 29 +++++++++++++++++------------ path_login.go | 13 ++++++++----- 5 files changed, 49 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 90202203..f53b172d 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,11 @@ require ( github.com/hashicorp/go-hclog v0.12.0 github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/go-sockaddr v1.0.2 + github.com/hashicorp/go-version v1.2.0 // indirect github.com/hashicorp/vault/api v1.0.5-0.20200215224050-f6547fa8e820 github.com/hashicorp/vault/sdk v0.1.14-0.20200215224050-f6547fa8e820 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/mapstructure v1.1.2 google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 // indirect k8s.io/api v0.0.0-20190409092523-d687e77c8ae9 diff --git a/go.sum b/go.sum index 85dbddc6..08b515c2 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,8 @@ github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr6 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/dep v0.5.4 h1:WfV5qbGwsBNUDhk+pfI6emWm7SdDFsnSWkqCMNG3BRs= +github.com/golang/dep v0.5.4/go.mod h1:6RZ2Wai7dSWk7qL55sDYk+8UPFqcW7all2KDBraPPFA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -72,8 +74,11 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -110,6 +115,10 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go. github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI= +github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= +github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= diff --git a/path_config.go b/path_config.go index 8880c401..a6e04502 100644 --- a/path_config.go +++ b/path_config.go @@ -57,6 +57,14 @@ extracted. Not every installation of Kuberentes exposes these keys.`, Name: "JWT Issuer", }, }, + "validate_iss_claim": { + Type: framework.TypeBool, + Description: "Optional JWT issuer validation. Allows to skip ISS validation, enabled by default", + Default: true, + DisplayAttrs: &framework.DisplayAttributes{ + Name: "JWT Issuer Validation", + }, + }, }, Callbacks: map[logical.Operation]framework.OperationFunc{ logical.UpdateOperation: b.pathConfigWrite, @@ -83,6 +91,7 @@ func (b *kubeAuthBackend) pathConfigRead(ctx context.Context, req *logical.Reque "kubernetes_ca_cert": config.CACert, "pem_keys": config.PEMKeys, "issuer": config.Issuer, + "validate_iss_claim": config.ValidateISSClaim, }, } @@ -100,6 +109,7 @@ func (b *kubeAuthBackend) pathConfigWrite(ctx context.Context, req *logical.Requ pemList := data.Get("pem_keys").([]string) caCert := data.Get("kubernetes_ca_cert").(string) issuer := data.Get("issuer").(string) + validateIssClaim := data.Get("validate_iss_claim").(bool) if len(pemList) == 0 && len(caCert) == 0 { return logical.ErrorResponse("one of pem_keys or kubernetes_ca_cert must be set"), nil } @@ -120,6 +130,7 @@ func (b *kubeAuthBackend) pathConfigWrite(ctx context.Context, req *logical.Requ CACert: caCert, TokenReviewerJWT: tokenReviewer, Issuer: issuer, + ValidateISSClaim: validateIssClaim, } var err error @@ -157,6 +168,8 @@ type kubeConfig struct { TokenReviewerJWT string `json:"token_reviewer_jwt"` // Issuer is the claim that specifies who issued the token Issuer string `json:"issuer"` + // ValidateISSClaim is an option to skip ISS validation + ValidateISSClaim bool `json:"validate_iss_claim"` } // PasrsePublicKeyPEM is used to parse RSA and ECDSA public keys from PEMs diff --git a/path_config_test.go b/path_config_test.go index 26978d261..4b2efa1d 100644 --- a/path_config_test.go +++ b/path_config_test.go @@ -16,6 +16,7 @@ func TestConfig_Read(t *testing.T) { "kubernetes_host": "host", "kubernetes_ca_cert": testCACert, "issuer": "", + "validate_iss_claim": true, } req := &logical.Request{ @@ -135,10 +136,11 @@ func TestConfig(t *testing.T) { } expected := &kubeConfig{ - PublicKeys: []interface{}{}, - PEMKeys: []string{}, - Host: "host", - CACert: testCACert, + PublicKeys: []interface{}{}, + PEMKeys: []string{}, + Host: "host", + CACert: testCACert, + ValidateISSClaim: true, } conf, err := b.(*kubeAuthBackend).config(context.Background(), storage) @@ -180,6 +182,7 @@ func TestConfig(t *testing.T) { Host: "host", CACert: testCACert, TokenReviewerJWT: jwtData, + ValidateISSClaim: true, } conf, err = b.(*kubeAuthBackend).config(context.Background(), storage) @@ -216,10 +219,11 @@ func TestConfig(t *testing.T) { } expected = &kubeConfig{ - PublicKeys: []interface{}{cert}, - PEMKeys: []string{testRSACert}, - Host: "host", - CACert: testCACert, + PublicKeys: []interface{}{cert}, + PEMKeys: []string{testRSACert}, + Host: "host", + CACert: testCACert, + ValidateISSClaim: true, } conf, err = b.(*kubeAuthBackend).config(context.Background(), storage) @@ -261,10 +265,11 @@ func TestConfig(t *testing.T) { } expected = &kubeConfig{ - PublicKeys: []interface{}{cert, cert2}, - PEMKeys: []string{testRSACert, testECCert}, - Host: "host", - CACert: testCACert, + PublicKeys: []interface{}{cert, cert2}, + PEMKeys: []string{testRSACert, testECCert}, + Host: "host", + CACert: testCACert, + ValidateISSClaim: true, } conf, err = b.(*kubeAuthBackend).config(context.Background(), storage) diff --git a/path_login.go b/path_login.go index be38486f..6530f4f2 100644 --- a/path_login.go +++ b/path_login.go @@ -203,11 +203,14 @@ func (b *kubeAuthBackend) parseAndValidateJWT(jwtStr string, role *roleStorageEn }, } - // set the expected issuer to the default kubernetes issuer if the config doesn't specify it - if config.Issuer != "" { - validator.SetIssuer(config.Issuer) - } else { - validator.SetIssuer(defaultJWTIssuer) + // perform ISS Claim validation if configured + if config.ValidateISSClaim { + // set the expected issuer to the default kubernetes issuer if the config doesn't specify it + if config.Issuer != "" { + validator.SetIssuer(config.Issuer) + } else { + validator.SetIssuer(defaultJWTIssuer) + } } // validate the audience if the role expects it From d8878cc43075996e3624c9b19e67799a80d6536d Mon Sep 17 00:00:00 2001 From: Roman Iuvshyn Date: Wed, 6 May 2020 18:18:01 +0300 Subject: [PATCH 2/6] update comment --- path_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/path_config.go b/path_config.go index a6e04502..813aa528 100644 --- a/path_config.go +++ b/path_config.go @@ -168,7 +168,7 @@ type kubeConfig struct { TokenReviewerJWT string `json:"token_reviewer_jwt"` // Issuer is the claim that specifies who issued the token Issuer string `json:"issuer"` - // ValidateISSClaim is an option to skip ISS validation + // ValidateISSClaim is optional parameter to allow to skip ISS validation ValidateISSClaim bool `json:"validate_iss_claim"` } From ef793f89f89ba3d7df341f16a39fdd883f3f16eb Mon Sep 17 00:00:00 2001 From: Roman Iuvshyn Date: Tue, 12 May 2020 11:54:56 +0300 Subject: [PATCH 3/6] rename config param to disable_iss_validation --- path_config.go | 38 ++++++++++++++++----------------- path_config_test.go | 52 ++++++++++++++++++++++----------------------- path_login.go | 2 +- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/path_config.go b/path_config.go index 813aa528..319dcde6 100644 --- a/path_config.go +++ b/path_config.go @@ -57,12 +57,12 @@ extracted. Not every installation of Kuberentes exposes these keys.`, Name: "JWT Issuer", }, }, - "validate_iss_claim": { + "disable_iss_validation": { Type: framework.TypeBool, - Description: "Optional JWT issuer validation. Allows to skip ISS validation, enabled by default", - Default: true, + Description: "Optional JWT issuer validation. Allows to skip ISS validation.", + Default: false, DisplayAttrs: &framework.DisplayAttributes{ - Name: "JWT Issuer Validation", + Name: "Disable JWT Issuer Validation", }, }, }, @@ -87,11 +87,11 @@ func (b *kubeAuthBackend) pathConfigRead(ctx context.Context, req *logical.Reque // Create a map of data to be returned resp := &logical.Response{ Data: map[string]interface{}{ - "kubernetes_host": config.Host, - "kubernetes_ca_cert": config.CACert, - "pem_keys": config.PEMKeys, - "issuer": config.Issuer, - "validate_iss_claim": config.ValidateISSClaim, + "kubernetes_host": config.Host, + "kubernetes_ca_cert": config.CACert, + "pem_keys": config.PEMKeys, + "issuer": config.Issuer, + "disable_iss_validation": config.DisableISSValidation, }, } @@ -109,7 +109,7 @@ func (b *kubeAuthBackend) pathConfigWrite(ctx context.Context, req *logical.Requ pemList := data.Get("pem_keys").([]string) caCert := data.Get("kubernetes_ca_cert").(string) issuer := data.Get("issuer").(string) - validateIssClaim := data.Get("validate_iss_claim").(bool) + disableIssValidation := data.Get("disable_iss_validation").(bool) if len(pemList) == 0 && len(caCert) == 0 { return logical.ErrorResponse("one of pem_keys or kubernetes_ca_cert must be set"), nil } @@ -124,13 +124,13 @@ func (b *kubeAuthBackend) pathConfigWrite(ctx context.Context, req *logical.Requ } config := &kubeConfig{ - PublicKeys: make([]interface{}, len(pemList)), - PEMKeys: pemList, - Host: host, - CACert: caCert, - TokenReviewerJWT: tokenReviewer, - Issuer: issuer, - ValidateISSClaim: validateIssClaim, + PublicKeys: make([]interface{}, len(pemList)), + PEMKeys: pemList, + Host: host, + CACert: caCert, + TokenReviewerJWT: tokenReviewer, + Issuer: issuer, + DisableISSValidation: disableIssValidation, } var err error @@ -168,8 +168,8 @@ type kubeConfig struct { TokenReviewerJWT string `json:"token_reviewer_jwt"` // Issuer is the claim that specifies who issued the token Issuer string `json:"issuer"` - // ValidateISSClaim is optional parameter to allow to skip ISS validation - ValidateISSClaim bool `json:"validate_iss_claim"` + // DisableISSValidation is optional parameter to allow to skip ISS validation + DisableISSValidation bool `json:"disable_iss_validation"` } // PasrsePublicKeyPEM is used to parse RSA and ECDSA public keys from PEMs diff --git a/path_config_test.go b/path_config_test.go index 4b2efa1d..d9f36b83 100644 --- a/path_config_test.go +++ b/path_config_test.go @@ -12,11 +12,11 @@ func TestConfig_Read(t *testing.T) { b, storage := getBackend(t) data := map[string]interface{}{ - "pem_keys": []string{testRSACert, testECCert}, - "kubernetes_host": "host", - "kubernetes_ca_cert": testCACert, - "issuer": "", - "validate_iss_claim": true, + "pem_keys": []string{testRSACert, testECCert}, + "kubernetes_host": "host", + "kubernetes_ca_cert": testCACert, + "issuer": "", + "disable_iss_validation": false, } req := &logical.Request{ @@ -136,11 +136,11 @@ func TestConfig(t *testing.T) { } expected := &kubeConfig{ - PublicKeys: []interface{}{}, - PEMKeys: []string{}, - Host: "host", - CACert: testCACert, - ValidateISSClaim: true, + PublicKeys: []interface{}{}, + PEMKeys: []string{}, + Host: "host", + CACert: testCACert, + DisableISSValidation: false, } conf, err := b.(*kubeAuthBackend).config(context.Background(), storage) @@ -177,12 +177,12 @@ func TestConfig(t *testing.T) { } expected = &kubeConfig{ - PublicKeys: []interface{}{}, - PEMKeys: []string{}, - Host: "host", - CACert: testCACert, - TokenReviewerJWT: jwtData, - ValidateISSClaim: true, + PublicKeys: []interface{}{}, + PEMKeys: []string{}, + Host: "host", + CACert: testCACert, + TokenReviewerJWT: jwtData, + DisableISSValidation: false, } conf, err = b.(*kubeAuthBackend).config(context.Background(), storage) @@ -219,11 +219,11 @@ func TestConfig(t *testing.T) { } expected = &kubeConfig{ - PublicKeys: []interface{}{cert}, - PEMKeys: []string{testRSACert}, - Host: "host", - CACert: testCACert, - ValidateISSClaim: true, + PublicKeys: []interface{}{cert}, + PEMKeys: []string{testRSACert}, + Host: "host", + CACert: testCACert, + DisableISSValidation: false, } conf, err = b.(*kubeAuthBackend).config(context.Background(), storage) @@ -265,11 +265,11 @@ func TestConfig(t *testing.T) { } expected = &kubeConfig{ - PublicKeys: []interface{}{cert, cert2}, - PEMKeys: []string{testRSACert, testECCert}, - Host: "host", - CACert: testCACert, - ValidateISSClaim: true, + PublicKeys: []interface{}{cert, cert2}, + PEMKeys: []string{testRSACert, testECCert}, + Host: "host", + CACert: testCACert, + DisableISSValidation: false, } conf, err = b.(*kubeAuthBackend).config(context.Background(), storage) diff --git a/path_login.go b/path_login.go index 6530f4f2..504700d8 100644 --- a/path_login.go +++ b/path_login.go @@ -204,7 +204,7 @@ func (b *kubeAuthBackend) parseAndValidateJWT(jwtStr string, role *roleStorageEn } // perform ISS Claim validation if configured - if config.ValidateISSClaim { + if !config.DisableISSValidation { // set the expected issuer to the default kubernetes issuer if the config doesn't specify it if config.Issuer != "" { validator.SetIssuer(config.Issuer) From 456328f26828c9e10edf8aac319506783ba2e0ac Mon Sep 17 00:00:00 2001 From: Roman Iuvshyn Date: Wed, 3 Jun 2020 22:45:56 +0300 Subject: [PATCH 4/6] update disable_iss_validation description --- path_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/path_config.go b/path_config.go index 319dcde6..a32f0cbe 100644 --- a/path_config.go +++ b/path_config.go @@ -59,7 +59,7 @@ extracted. Not every installation of Kuberentes exposes these keys.`, }, "disable_iss_validation": { Type: framework.TypeBool, - Description: "Optional JWT issuer validation. Allows to skip ISS validation.", + Description: "Disable JWT issuer validation. Allows to skip ISS validation.", Default: false, DisplayAttrs: &framework.DisplayAttributes{ Name: "Disable JWT Issuer Validation", From 5565e71b45ebec7db27e41ef5425c3316722c5d6 Mon Sep 17 00:00:00 2001 From: Roman Iuvshyn Date: Wed, 3 Jun 2020 23:05:01 +0300 Subject: [PATCH 5/6] add test for disable_iss_validation, go mod tidy --- go.mod | 1 - go.sum | 7 ------- path_config_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index f53b172d..0730b590 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,6 @@ require ( github.com/hashicorp/vault/api v1.0.5-0.20200215224050-f6547fa8e820 github.com/hashicorp/vault/sdk v0.1.14-0.20200215224050-f6547fa8e820 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect - github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/mapstructure v1.1.2 google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 // indirect k8s.io/api v0.0.0-20190409092523-d687e77c8ae9 diff --git a/go.sum b/go.sum index 08b515c2..b9307b2a 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,6 @@ github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr6 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/dep v0.5.4 h1:WfV5qbGwsBNUDhk+pfI6emWm7SdDFsnSWkqCMNG3BRs= -github.com/golang/dep v0.5.4/go.mod h1:6RZ2Wai7dSWk7qL55sDYk+8UPFqcW7all2KDBraPPFA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -74,7 +72,6 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= @@ -115,10 +112,6 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go. github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI= -github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= -github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= diff --git a/path_config_test.go b/path_config_test.go index d9f36b83..90c2e6ce 100644 --- a/path_config_test.go +++ b/path_config_test.go @@ -280,6 +280,47 @@ func TestConfig(t *testing.T) { if !reflect.DeepEqual(expected, conf) { t.Fatalf("expected did not match actual: expected %#v\n got %#v\n", expected, conf) } + + // Test success with disabled iss validation + data = map[string]interface{}{ + "kubernetes_host": "host", + "kubernetes_ca_cert": testCACert, + "disable_iss_validation": true, + } + + req = &logical.Request{ + Operation: logical.CreateOperation, + Path: configPath, + Storage: storage, + Data: data, + } + + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + cert, err = parsePublicKeyPEM([]byte(testRSACert)) + if err != nil { + t.Fatal(err) + } + + expected = &kubeConfig{ + PublicKeys: []interface{}{}, + PEMKeys: []string{}, + Host: "host", + CACert: testCACert, + DisableISSValidation: true, + } + + conf, err = b.(*kubeAuthBackend).config(context.Background(), storage) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(expected, conf) { + t.Fatalf("expected did not match actual: expected %#v\n got %#v\n", expected, conf) + } } var testRSACert string = `-----BEGIN CERTIFICATE----- From aa646c86ec058994c3277dfef8e9bc92ad56122e Mon Sep 17 00:00:00 2001 From: Roman Iuvshyn Date: Thu, 4 Jun 2020 12:08:29 +0300 Subject: [PATCH 6/6] Add iss validation login tests --- path_login_test.go | 165 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/path_login_test.go b/path_login_test.go index 893a74f7..661b53a0 100644 --- a/path_login_test.go +++ b/path_login_test.go @@ -561,6 +561,171 @@ func TestAliasLookAhead(t *testing.T) { } } +func TestLoginIssValidation(t *testing.T) { + b, storage := setupBackend(t, testNoPEMs, testName, testNamespace) + + // test iss validation enabled with default "kubernetes/serviceaccount" issuer + data := map[string]interface{}{ + "kubernetes_host": "host", + "kubernetes_ca_cert": testCACert, + "disable_iss_validation": false, + } + + req := &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: storage, + Data: data, + } + + resp, err := b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + // test successful login with default issuer + data = map[string]interface{}{ + "role": "plugin-test", + "jwt": jwtData, + } + + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "login", + Storage: storage, + Data: data, + Connection: &logical.Connection{ + RemoteAddr: "127.0.0.1", + }, + } + + // test iss validation enabled with explicitly defined issuer + data = map[string]interface{}{ + "kubernetes_host": "host", + "kubernetes_ca_cert": testCACert, + "disable_iss_validation": false, + "issuer": "kubernetes/serviceaccount", + } + + req = &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: storage, + Data: data, + } + + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + // test successful login with explicitly defined issuer + data = map[string]interface{}{ + "role": "plugin-test", + "jwt": jwtData, + } + + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "login", + Storage: storage, + Data: data, + Connection: &logical.Connection{ + RemoteAddr: "127.0.0.1", + }, + } + + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + // test iss validation enabled with custom issuer + data = map[string]interface{}{ + "kubernetes_host": "host", + "kubernetes_ca_cert": testCACert, + "disable_iss_validation": false, + "issuer": "custom-issuer", + } + + req = &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: storage, + Data: data, + } + + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + // test login fail with enabled iss validation and custom issuer + data = map[string]interface{}{ + "role": "plugin-test", + "jwt": jwtData, + } + + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "login", + Storage: storage, + Data: data, + Connection: &logical.Connection{ + RemoteAddr: "127.0.0.1", + }, + } + + resp, err = b.HandleRequest(context.Background(), req) + if err == nil { + t.Fatal("expected error") + } + if err.Error() != "claim \"iss\" is invalid" { + t.Fatalf("unexpected error: %s", err) + } + + // test iss validation disabled with custom issuer + data = map[string]interface{}{ + "kubernetes_host": "host", + "kubernetes_ca_cert": testCACert, + "disable_iss_validation": true, + "issuer": "custom-issuer", + } + + req = &logical.Request{ + Operation: logical.CreateOperation, + Path: "config", + Storage: storage, + Data: data, + } + + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } + + // test login success with disabled iss validation and custom issuer + data = map[string]interface{}{ + "role": "plugin-test", + "jwt": jwtData, + } + + req = &logical.Request{ + Operation: logical.UpdateOperation, + Path: "login", + Storage: storage, + Data: data, + Connection: &logical.Connection{ + RemoteAddr: "127.0.0.1", + }, + } + + resp, err = b.HandleRequest(context.Background(), req) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%s resp:%#v\n", err, resp) + } +} + var jwtData = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InZhdWx0LWF1dGgtdG9rZW4tdDVwY24iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoidmF1bHQtYXV0aCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImQ3N2Y4OWJjLTkwNTUtMTFlNy1hMDY4LTA4MDAyNzZkOTliZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnZhdWx0LWF1dGgifQ.HKUcqgrvan5ZC_mnpaMEx4RW3KrhfyH_u8G_IA2vUfkLK8tH3T7fJuJaPr7W6K_BqCrbeM5y3owszOzb4NR0Lvw6GBt2cFcen2x1Ua4Wokr0bJjTT7xQOIOw7UvUDyVS17wAurlfUnmWMwMMMOebpqj5K1t6GnyqghH1wPdHYRGX-q5a6C323dBCgM5t6JY_zTTaBgM6EkFq0poBaifmSMiJRPrdUN_-IgyK8fgQRiFYYkgS6DMIU4k4nUOb_sUFf5xb8vMs3SMteKiuWFAIt4iszXTj5IyBUNqe0cXA3zSY3QiNCV6bJ2CWW0Qf9WDtniT79VAqcR4GYaTC_gxjNA" var jwtBadServiceAccount = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InZhdWx0LWludmFsaWQtdG9rZW4tZ3ZxcHQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoidmF1bHQtaW52YWxpZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjA0NGZkNGYxLTk3NGQtMTFlNy05YTE1LTA4MDAyNzZkOTliZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnZhdWx0LWludmFsaWQifQ.BcoOdu5BrIchp66Zl8-dY7HcGHJrVXrUh4SNTlIHR6vDaNH29B7JuI_-B1pvW9GpzQnc-XjZyua_wfSssqe-KYJcq--Qh0yQfbbLE5rvEipBCHH341IqGaTHaBVip8zXqYE-bt-7J6vAH8Azvw46iatDC73tKxh46xDuxK0gKjdprW4cOklDx6ZSxEHpu63ftLYgAgk9c0MUJxKWhu9Jk0aye5pTj_iyBbBy8llZNGaw2gxvhPzFVUEHZUlTRiSIbmPmNqep48RiJoWrq6FM1lijvrtT5y-E7aFk6TpW2BH3VDHy8k10sMIxuRAYrGB3tpUKNyVDI3tJOi_xY7iJvw"