From b8d933fc1001ccadb60ffea08a0ec8bcf3bfe2da Mon Sep 17 00:00:00 2001 From: dnitsch Date: Tue, 7 Feb 2023 10:58:50 +0000 Subject: [PATCH 1/6] fix: add helper for AWS --- go.mod | 4 ++ go.sum | 76 ++++++++++++++++++++++++++++++++++++- pkg/generator/hashivault.go | 40 ++++++++++++++++--- 3 files changed, 113 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 1217b74..4ae99f6 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 // indirect github.com/armon/go-metrics v0.3.9 // indirect github.com/armon/go-radix v1.0.0 // indirect + github.com/aws/aws-sdk-go v1.30.27 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/fatih/color v1.7.0 // indirect @@ -42,6 +43,7 @@ require ( github.com/hashicorp/go-plugin v1.4.5 // indirect github.com/hashicorp/go-retryablehttp v0.6.6 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 // indirect github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect @@ -61,6 +63,7 @@ require ( github.com/oklog/run v1.0.0 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.9.0 // indirect @@ -93,6 +96,7 @@ require ( github.com/axw/gocov v1.1.0 github.com/googleapis/gax-go/v2 v2.7.0 github.com/hashicorp/vault/api v1.8.2 + github.com/hashicorp/vault/api/auth/aws v0.3.0 github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jstemmer/go-junit-report v1.0.0 diff --git a/go.sum b/go.sum index 017577b..b409626 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y= cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0= cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= @@ -29,11 +30,14 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aws/aws-sdk-go v1.30.27 h1:9gPjZWVDSoQrBO2AvqrWObS6KAZByfEJxQoCYo4ZfK0= +github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/PgrhY= github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/config v1.18.8 h1:lDpy0WM8AHsywOnVrOHaSMfpaiV2igOw8D7svkFkXVA= @@ -76,8 +80,11 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -85,15 +92,25 @@ github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= +github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -108,12 +125,15 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= @@ -138,6 +158,7 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbez github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -146,14 +167,17 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= @@ -161,13 +185,19 @@ github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 h1:W9WN8p6moV1fjKLkeqEgkAMu5rauy9QeYDAmIaPuuiA= +github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6/go.mod h1:MpCPSPGLDILGb4JMm94/mMi3YysIqsXzGCzkEZjcjXg= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -180,8 +210,11 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/vault/api v1.8.0/go.mod h1:uJrw6D3y9Rv7hhmS17JQC50jbPDAZdjZoTtrCCxxs7E= github.com/hashicorp/vault/api v1.8.2 h1:C7OL9YtOtwQbTKI9ogB0A1wffRbCN+rH/LLCHO3d8HM= github.com/hashicorp/vault/api v1.8.2/go.mod h1:ML8aYzBIhY5m1MD1B2Q0JV89cC85YVH4t5kBaZiyVaE= +github.com/hashicorp/vault/api/auth/aws v0.3.0 h1:CGUM1rB6JFiX9HhBrkbpdRiduiFF6+KfC3BVXrtqkWw= +github.com/hashicorp/vault/api/auth/aws v0.3.0/go.mod h1:jkbyCqeuaEJd7Tz4JikjJt61hAAXPY9YuWZ/GaGIovs= github.com/hashicorp/vault/sdk v0.6.0 h1:6Z+In5DXHiUfZvIZdMx7e2loL1PPyDjA4bVh9ZTIAhs= github.com/hashicorp/vault/sdk v0.6.0/go.mod h1:+DRpzoXIdMvKc88R4qxr+edwy/RvH5QK8itmxLiDHLc= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= @@ -189,7 +222,10 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKe github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -201,21 +237,27 @@ github.com/jstemmer/go-junit-report v1.0.0/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= @@ -226,6 +268,7 @@ github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMK github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 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= @@ -249,6 +292,7 @@ github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -265,6 +309,9 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= @@ -288,6 +335,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -296,29 +344,37 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -335,14 +391,21 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -359,22 +422,30 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ= google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c h1:S34D59DS2GWOEwWNt4fYmTcFrtlOgukG2k9WsomZ7tg= google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -392,12 +463,15 @@ google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/generator/hashivault.go b/pkg/generator/hashivault.go index d776988..d840b9c 100644 --- a/pkg/generator/hashivault.go +++ b/pkg/generator/hashivault.go @@ -3,11 +3,14 @@ package generator import ( "context" "encoding/json" + "fmt" + "os" "strings" "github.com/dnitsch/configmanager/pkg/log" vault "github.com/hashicorp/vault/api" + auth "github.com/hashicorp/vault/api/auth/aws" ) // vaultHelper provides a broken up string @@ -16,10 +19,6 @@ type vaultHelper struct { token string } -type hashiVaultClient interface { - KVv2(mountPath string) *vault.KVv2 -} - type hashiVaultApi interface { Get(ctx context.Context, secretPath string) (*vault.KVSecret, error) } @@ -31,6 +30,7 @@ type VaultStore struct { } func NewVaultStore(ctx context.Context, token, tokenSeparator, keySeparator string) (*VaultStore, error) { + var client *vault.Client config := vault.DefaultConfig() vt := splitToken(stripPrefix(token, HashicorpVaultPrefix, tokenSeparator, keySeparator)) client, err := vault.NewClient(config) @@ -38,6 +38,14 @@ func NewVaultStore(ctx context.Context, token, tokenSeparator, keySeparator stri log.Errorf("unable to initialize Vault client: %v", err) } + if strings.HasPrefix(os.Getenv("VAULT_TOKEN"), "aws_iam") { + awsclient, err := newVaultStoreWithAWSAuthIAM(client, "todo_get_from_token_or_other") + if err != nil { + return nil, err + } + client = awsclient + } + return &VaultStore{ svc: client.KVv2(vt.path), ctx: ctx, @@ -45,9 +53,29 @@ func NewVaultStore(ctx context.Context, token, tokenSeparator, keySeparator stri }, nil } -// func newVaultStore(ctx context.Context) (*VaultStore, error) { +// newVaultStoreWithAWSAuthIAM returns an initialised client with AWSIAMAuth +func newVaultStoreWithAWSAuthIAM(client *vault.Client, role string) (*vault.Client, error) { + if len(role) < 1 { + return nil, fmt.Errorf("role provided is empty, EC2 auth not supported") + } + awsAuth, err := auth.NewAWSAuth( + auth.WithRole(role), // if not provided, Vault will fall back on looking for a role with the IAM role name if you're using the iam auth type, or the EC2 instance's AMI id if using the ec2 auth type + ) + if err != nil { + return nil, fmt.Errorf("unable to initialize AWS auth method: %w", err) + } + + authInfo, err := client.Auth().Login(context.Background(), awsAuth) -// } + if err != nil { + return nil, fmt.Errorf("unable to login to AWS auth method: %w", err) + } + if authInfo == nil { + return nil, fmt.Errorf("no auth info was returned after login") + } + + return client, nil +} // setToken already happens in Vault constructor // no need to re-set it here From 29016816b3e9b776e4e90dd38af7f6f8532ce378 Mon Sep 17 00:00:00 2001 From: dnitsch Date: Tue, 7 Feb 2023 14:43:33 +0000 Subject: [PATCH 2/6] fix: pr ci --- .github/workflows/build.yml | 1 - .github/workflows/pr.yml | 14 ++++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8829de..939f45e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,4 +68,3 @@ jobs: -Dsonar.projectVersion=${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} -Dsonar.go.coverage.reportPaths=/github/workspace/.coverage/out -Dsonar.go.tests.reportPaths=/github/workspace/.coverage/report-junit.xml - -X diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index e10f92d..04134d9 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -22,11 +22,6 @@ jobs: - name: Set SemVer Version uses: gittools/actions/gitversion/execute@v0.9.15 id: gitversion - - - name: echo VERSIONS - run: | - echo "REVISION -> $GITHUB_SHA" - echo "VERSION -> $GITVERSION_SEMVER" pr: runs-on: ubuntu-latest container: @@ -39,8 +34,10 @@ jobs: - uses: actions/checkout@v3 - name: install deps run: | - apt update && apt install jq -y - make REVISION=$GITHUB_SHA install + apt-get update && apt-get install -y jq git + git config --global --add safe.directory "$GITHUB_WORKSPACE" + git config user.email ${{ github.actor }}-ci@gha.org + git config user.name ${{ github.actor }} - name: make test run: | make REVISION=$GITHUB_SHA test @@ -60,5 +57,6 @@ jobs: args: # Unique keys of your project and organization. You can find them in SonarCloud > Information (bottom-left menu) # mandatory - -Dsonar.projectVersion=$SEMVER + -Dsonar.projectVersion=${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} -Dsonar.go.coverage.reportPaths=/github/workspace/.coverage/out + -Dsonar.go.tests.reportPaths=/github/workspace/.coverage/report-junit.xml From 9768fbf2e125e315836bb32d5a0567d4738de0db Mon Sep 17 00:00:00 2001 From: dnitsch Date: Thu, 9 Feb 2023 14:28:08 +0000 Subject: [PATCH 3/6] feat: add hashivault AWS IAM Auth minor CI tweak +semver: feat --- .github/workflows/build.yml | 10 +- .github/workflows/pr.yml | 8 +- .github/workflows/release.yml | 6 +- hack/release.sh | 1 + pkg/generator/config.go | 41 ++++++++ pkg/generator/config_test.go | 85 +++++++++++++++ pkg/generator/generator.go | 12 ++- pkg/generator/generator_test.go | 10 +- pkg/generator/hashivault.go | 45 +++++--- pkg/generator/hashivault_test.go | 150 ++++++++++++++++++++++----- pkg/generator/keyvault.go | 27 +++-- pkg/generator/keyvault_test.go | 30 +++--- pkg/generator/secretsmanager.go | 13 ++- pkg/generator/secretsmanager_test.go | 2 +- pkg/generator/strategy.go | 10 +- pkg/generator/strategy_test.go | 24 ++--- 16 files changed, 361 insertions(+), 113 deletions(-) create mode 100644 pkg/generator/config_test.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 939f45e..940cae9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ on: branches: [ master, main ] jobs: - set-deps-dotnet-poop-here: + set-version: runs-on: ubuntu-latest container: image: mcr.microsoft.com/dotnet/sdk:6.0 @@ -31,10 +31,10 @@ jobs: runs-on: ubuntu-latest container: image: golang:1.19-bullseye - needs: set-deps-dotnet-poop-here + needs: set-version env: - SEMVER: ${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} - GIT_TAG: ${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} + SEMVER: ${{ needs.set-version.outputs.semVer }} + GIT_TAG: ${{ needs.set-version.outputs.semVer }} GOVCS: false steps: - uses: actions/checkout@v3 @@ -65,6 +65,6 @@ jobs: # Additional arguments for the sonarcloud scanner args: # mandatory - -Dsonar.projectVersion=${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} + -Dsonar.projectVersion=${{ needs.set-version.outputs.semVer }} -Dsonar.go.coverage.reportPaths=/github/workspace/.coverage/out -Dsonar.go.tests.reportPaths=/github/workspace/.coverage/report-junit.xml diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index cc720e2..6e41776 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -5,7 +5,7 @@ on: branches: [ master, main ] jobs: - set-deps-dotnet-poop-here: + set-version: runs-on: ubuntu-latest container: image: mcr.microsoft.com/dotnet/sdk:6.0 @@ -26,10 +26,10 @@ jobs: runs-on: ubuntu-latest container: image: golang:1.19-bullseye - needs: set-deps-dotnet-poop-here + needs: set-version env: REVISION: $GITHUB_SHA - SEMVER: ${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} + SEMVER: ${{ needs.set-version.outputs.semVer }} steps: - uses: actions/checkout@v3 - name: install deps @@ -54,6 +54,6 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret) with: args: - -Dsonar.projectVersion=${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} + -Dsonar.projectVersion=${{ needs.set-version.outputs.semVer }} -Dsonar.go.coverage.reportPaths=/github/workspace/.coverage/out -Dsonar.go.tests.reportPaths=/github/workspace/.coverage/report-junit.xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4bef644..3c2abe0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: - completed jobs: - set-deps-dotnet-poop-here: + set-version: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} container: @@ -36,9 +36,9 @@ jobs: image: golang:1.19-bullseye env: FOO: Bar - needs: set-deps-dotnet-poop-here + needs: set-version env: - SEMVER: ${{ needs.set-deps-dotnet-poop-here.outputs.semVer }} + SEMVER: ${{ needs.set-version.outputs.semVer }} steps: - uses: actions/checkout@v3 with: diff --git a/hack/release.sh b/hack/release.sh index 90b3c5f..75cc672 100755 --- a/hack/release.sh +++ b/hack/release.sh @@ -6,5 +6,6 @@ upload_url=https://uploads.github.com/repos/$OWNER/$NAME/releases/$id/assets for asset in dist/*; do \ name=$(echo $asset | cut -c 6-) + echo "pkg name: $name" curl -u $OWNER:$PAT -H "Content-Type: application/x-binary" -X POST --data-binary "@$asset" "$upload_url?name=$name" done diff --git a/pkg/generator/config.go b/pkg/generator/config.go index 8eac553..48544dc 100644 --- a/pkg/generator/config.go +++ b/pkg/generator/config.go @@ -1,10 +1,28 @@ package generator +import ( + "regexp" + "strings" +) + +// TokenConfigVars +type TokenConfigVars struct { + Token string + // AWS IAM Role for Vault AWS IAM Auth + Role string + // where supported a version of the secret can be specified + // + // e.g. HashiVault or AWS SecretsManager + // + Version string +} + // GenVarsConfig defines the input config object to be passed type GenVarsConfig struct { outpath string tokenSeparator string keySeparator string + // parseAdditionalVars func(token string) TokenConfigVars } // NewConfig @@ -49,3 +67,26 @@ func (c *GenVarsConfig) TokenSeparator() string { func (c *GenVarsConfig) KeySeparator() string { return c.keySeparator } + +func (c GenVarsConfig) ParseTokenVars(token string) TokenConfigVars { + tc := TokenConfigVars{} + // strip anything in [] + vars := regexp.MustCompile(`\[.+\]`) + rawVars := vars.FindString(token) + // extract [role:,version:] + if rawVars != "" { + role := regexp.MustCompile(`role:(.*?)(?:,|])`).FindStringSubmatch(rawVars) + if len(role) > 0 { + tc.Role = role[1] + } + version := regexp.MustCompile(`version:(.*?)(?:,|])`).FindStringSubmatch(rawVars) + if len(version) > 0 { + tc.Version = version[1] + } + tc.Token = strings.ReplaceAll(token, rawVars, "") + // tc.Role = + return tc + } + tc.Token = token + return tc +} diff --git a/pkg/generator/config_test.go b/pkg/generator/config_test.go new file mode 100644 index 0000000..d32d9ff --- /dev/null +++ b/pkg/generator/config_test.go @@ -0,0 +1,85 @@ +package generator_test + +import ( + "testing" + + "github.com/dnitsch/configmanager/internal/testutils" + "github.com/dnitsch/configmanager/pkg/generator" +) + +func TestParseTokens(t *testing.T) { + ttests := map[string]struct { + config generator.GenVarsConfig + rawToken string + expect generator.TokenConfigVars + }{ + "role, version specified": { + *generator.NewConfig(), + `FOO://basjh/dskjuds/123|d88[role:arn:aws:iam::1111111:role/i-orchestration,version:1082313]`, + generator.TokenConfigVars{ + Token: `FOO://basjh/dskjuds/123|d88`, + Role: `arn:aws:iam::1111111:role/i-orchestration`, + Version: `1082313`, + }, + }, + "version, role specified": { + *generator.NewConfig(), + `FOO://basjh/dskjuds/123|d88[version:1082313,role:arn:aws:iam::1111111:role/i-orchestration]`, + generator.TokenConfigVars{ + Token: `FOO://basjh/dskjuds/123|d88`, + Role: `arn:aws:iam::1111111:role/i-orchestration`, + Version: `1082313`, + }, + }, + "version only specified": { + *generator.NewConfig(), + `FOO://basjh/dskjuds/123|d88[version:1082313]`, + generator.TokenConfigVars{ + Token: `FOO://basjh/dskjuds/123|d88`, + Role: ``, + Version: `1082313`, + }, + }, + "role only specified": { + *generator.NewConfig(), + `FOO://basjh/dskjuds/123|d88[role:arn:aws:iam::1111111:role/i-orchestration]`, + generator.TokenConfigVars{ + Token: `FOO://basjh/dskjuds/123|d88`, + Role: `arn:aws:iam::1111111:role/i-orchestration`, + Version: ``, + }, + }, + "no additional config specified": { + *generator.NewConfig(), + `FOO://basjh/dskjuds/123|d88`, + generator.TokenConfigVars{ + Token: `FOO://basjh/dskjuds/123|d88`, + Role: ``, + Version: ``, + }, + }, + "additional config specified but empty": { + *generator.NewConfig(), + `FOO://basjh/dskjuds/123`, + generator.TokenConfigVars{ + Token: `FOO://basjh/dskjuds/123`, + Role: ``, + Version: ``, + }, + }, + } + for name, tt := range ttests { + t.Run(name, func(t *testing.T) { + got := tt.config.ParseTokenVars(tt.rawToken) + if got.Role != tt.expect.Role { + t.Errorf(testutils.TestPhraseWithContext, "role incorrect", got.Role, tt.expect.Role) + } + if got.Version != tt.expect.Version { + t.Errorf(testutils.TestPhraseWithContext, "version incorrect", got.Version, tt.expect.Version) + } + if got.Token != tt.expect.Token { + t.Errorf(testutils.TestPhraseWithContext, "token incorrect", got.Token, tt.expect.Token) + } + }) + } +} diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 7338783..da9c77d 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -170,7 +170,7 @@ type chanResp struct { type retrieveIface interface { RetrieveByToken(ctx context.Context, impl genVarsStrategy, prefix ImplementationPrefix, in string) chanResp - SelectImplementation(ctx context.Context, prefix ImplementationPrefix, in string, config *GenVarsConfig) (genVarsStrategy, error) + SelectImplementation(ctx context.Context, prefix ImplementationPrefix, in string, config GenVarsConfig) (genVarsStrategy, error) } // generate checks if any tokens found @@ -191,15 +191,17 @@ func (c *GenVars) generate(rawMap map[string]string, rs retrieveIface) error { wg.Add(initChanLen) for token, prefix := range rawMap { - go func(a string, p ImplementationPrefix) { + // take value from config allocation on a per iteration basis + conf := c.Config() + go func(prfx ImplementationPrefix, tkn string, conf GenVarsConfig) { defer wg.Done() - strategy, err := rs.SelectImplementation(c.ctx, p, a, c.Config()) + strategy, err := rs.SelectImplementation(c.ctx, prfx, tkn, conf) if err != nil { outCh <- chanResp{err: err} return } - outCh <- rs.RetrieveByToken(c.ctx, strategy, p, a) - }(token, ImplementationPrefix(prefix)) + outCh <- rs.RetrieveByToken(c.ctx, strategy, prfx, tkn) + }(ImplementationPrefix(prefix), token, *conf) } go func() { diff --git a/pkg/generator/generator_test.go b/pkg/generator/generator_test.go index ed76478..56ab54b 100644 --- a/pkg/generator/generator_test.go +++ b/pkg/generator/generator_test.go @@ -296,13 +296,13 @@ func Test_listToString(t *testing.T) { type mockRetrieve struct //func(ctx context.Context, impl genVarsStrategy, prefix ImplementationPrefix, in string) chanResp { r func(ctx context.Context, impl genVarsStrategy, prefix ImplementationPrefix, in string) chanResp - s func(ctx context.Context, prefix ImplementationPrefix, in string, config *GenVarsConfig) (genVarsStrategy, error) + s func(ctx context.Context, prefix ImplementationPrefix, in string, config GenVarsConfig) (genVarsStrategy, error) } func (m mockRetrieve) RetrieveByToken(ctx context.Context, impl genVarsStrategy, prefix ImplementationPrefix, in string) chanResp { return m.r(ctx, impl, prefix, in) } -func (m mockRetrieve) SelectImplementation(ctx context.Context, prefix ImplementationPrefix, in string, config *GenVarsConfig) (genVarsStrategy, error) { +func (m mockRetrieve) SelectImplementation(ctx context.Context, prefix ImplementationPrefix, in string, config GenVarsConfig) (genVarsStrategy, error) { return m.s(ctx, prefix, in, config) } @@ -338,7 +338,7 @@ func Test_generate(t *testing.T) { value: "bar", } }, - s: func(ctx context.Context, prefix ImplementationPrefix, in string, config *GenVarsConfig) (genVarsStrategy, error) { + s: func(ctx context.Context, prefix ImplementationPrefix, in string, config GenVarsConfig) (genVarsStrategy, error) { return &mockImpl{"foo", "bar", nil}, nil }} }, @@ -358,7 +358,7 @@ func Test_generate(t *testing.T) { err: fmt.Errorf("unable to retrieve"), } }, - s: func(ctx context.Context, prefix ImplementationPrefix, in string, config *GenVarsConfig) (genVarsStrategy, error) { + s: func(ctx context.Context, prefix ImplementationPrefix, in string, config GenVarsConfig) (genVarsStrategy, error) { return &mockImpl{"foo", "bar", nil}, nil }} }, @@ -377,7 +377,7 @@ func Test_generate(t *testing.T) { err: fmt.Errorf("unable to retrieve"), } }, - s: func(ctx context.Context, prefix ImplementationPrefix, in string, config *GenVarsConfig) (genVarsStrategy, error) { + s: func(ctx context.Context, prefix ImplementationPrefix, in string, config GenVarsConfig) (genVarsStrategy, error) { return nil, fmt.Errorf("implementation not found for input string: %s", in) }} }, diff --git a/pkg/generator/hashivault.go b/pkg/generator/hashivault.go index d840b9c..fdfd558 100644 --- a/pkg/generator/hashivault.go +++ b/pkg/generator/hashivault.go @@ -24,42 +24,52 @@ type hashiVaultApi interface { } type VaultStore struct { - svc hashiVaultApi - ctx context.Context - token string + svc hashiVaultApi + ctx context.Context + config TokenConfigVars + token string } -func NewVaultStore(ctx context.Context, token, tokenSeparator, keySeparator string) (*VaultStore, error) { +func NewVaultStore(ctx context.Context, token string, conf GenVarsConfig) (*VaultStore, error) { var client *vault.Client + + tc := conf.ParseTokenVars(token) + + imp := &VaultStore{ + ctx: ctx, + config: tc, + } + config := vault.DefaultConfig() - vt := splitToken(stripPrefix(token, HashicorpVaultPrefix, tokenSeparator, keySeparator)) + + vt := splitToken(stripPrefix(tc.Token, HashicorpVaultPrefix, conf.TokenSeparator(), conf.KeySeparator())) + + imp.token = vt.token + client, err := vault.NewClient(config) if err != nil { - log.Errorf("unable to initialize Vault client: %v", err) + return nil, fmt.Errorf("unable to initialize Vault client: %v", err) } if strings.HasPrefix(os.Getenv("VAULT_TOKEN"), "aws_iam") { - awsclient, err := newVaultStoreWithAWSAuthIAM(client, "todo_get_from_token_or_other") + awsclient, err := newVaultStoreWithAWSAuthIAM(client, conf.ParseTokenVars(token).Role) if err != nil { return nil, err } client = awsclient } - - return &VaultStore{ - svc: client.KVv2(vt.path), - ctx: ctx, - token: vt.token, - }, nil + imp.svc = client.KVv2(vt.path) + return imp, nil } // newVaultStoreWithAWSAuthIAM returns an initialised client with AWSIAMAuth +// EC2 auth type is not supported currently func newVaultStoreWithAWSAuthIAM(client *vault.Client, role string) (*vault.Client, error) { if len(role) < 1 { return nil, fmt.Errorf("role provided is empty, EC2 auth not supported") } awsAuth, err := auth.NewAWSAuth( - auth.WithRole(role), // if not provided, Vault will fall back on looking for a role with the IAM role name if you're using the iam auth type, or the EC2 instance's AMI id if using the ec2 auth type + auth.WithRole(role), ) if err != nil { return nil, fmt.Errorf("unable to initialize AWS auth method: %w", err) @@ -118,8 +128,11 @@ func (imp *VaultStore) getTokenValue(v *retrieveStrategy) (string, error) { func splitToken(token string) vaultHelper { vh := vaultHelper{} - s := strings.Split(strings.TrimPrefix(token, "/"), "/") - vh.token = strings.Join(s[1:], "/") + // split token to extract the mount path + s := strings.Split(strings.TrimPrefix(token, "/"), "___") + // grab token and trim prefix if slash + vh.token = strings.TrimPrefix(strings.Join(s[1:], ""), "/") + // assign mount path as extracted from input token vh.path = s[0] return vh } diff --git a/pkg/generator/hashivault_test.go b/pkg/generator/hashivault_test.go index 6ccbad8..c405584 100644 --- a/pkg/generator/hashivault_test.go +++ b/pkg/generator/hashivault_test.go @@ -17,10 +17,11 @@ func TestMountPathExtract(t *testing.T) { keySeparator string expect string }{ - "without leading slash": {"VAULT://secret/demo/configmanager", "://", "|", "secret"}, - "with leading slash": {"VAULT:///secret/demo/configmanager", "://", "|", "secret"}, - "with underscore in path name": {"VAULT://_secret/demo/configmanager", "://", "|", "_secret"}, - "with double underscore in path name": {"VAULT://__secret/demo/configmanager", "://", "|", "__secret"}, + "without leading slash": {"VAULT://secret___/demo/configmanager", "://", "|", "secret"}, + "with leading slash": {"VAULT:///secret___/demo/configmanager", "://", "|", "secret"}, + "with underscore in path name": {"VAULT://_secret___/demo/configmanager", "://", "|", "_secret"}, + "with double underscore in path name": {"VAULT://__secret___/demo/configmanager", "://", "|", "__secret"}, + "with multiple paths in mountpath": {"VAULT://secret/bar/path___/demo/configmanager", "://", "|", "secret/bar/path"}, } for name, tt := range ttests { t.Run(name, func(t *testing.T) { @@ -45,8 +46,9 @@ func TestVaultScenarios(t *testing.T) { conf GenVarsConfig expect string mockClient func(t *testing.T) hashiVaultApi + setupEnv func() func() }{ - "happy return": {"VAULT://secret/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{"foo":"test2130-9sd-0ds"}`, + "happy return": {"VAULT://secret___/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{"foo":"test2130-9sd-0ds"}`, func(t *testing.T) hashiVaultApi { return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() @@ -58,8 +60,14 @@ func TestVaultScenarios(t *testing.T) { return &vault.KVSecret{Data: m}, nil }) }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, }, - "incorrect json": {"VAULT://secret/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `json: unsupported type: func() error`, + "incorrect json": {"VAULT://secret___/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `json: unsupported type: func() error`, func(t *testing.T) hashiVaultApi { return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() @@ -71,21 +79,37 @@ func TestVaultScenarios(t *testing.T) { return &vault.KVSecret{Data: m}, nil }) }, - }, - "another return": {"VAULT://secret/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{"foo1":"test2130-9sd-0ds","foo2":"dsfsdf3454456"}`, func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { - t.Helper() - if secretPath != "some/other/foo2" { - t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() } - m := make(map[string]interface{}) - m["foo1"] = "test2130-9sd-0ds" - m["foo2"] = "dsfsdf3454456" - return &vault.KVSecret{Data: m}, nil - }) + }, }, + "another return": { + "VAULT://secret/engine1___/some/other/foo2", + GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, + `{"foo1":"test2130-9sd-0ds","foo2":"dsfsdf3454456"}`, + func(t *testing.T) hashiVaultApi { + return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) + } + m := make(map[string]interface{}) + m["foo1"] = "test2130-9sd-0ds" + m["foo2"] = "dsfsdf3454456" + return &vault.KVSecret{Data: m}, nil + }) + }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, }, - "not found": {"VAULT://secret/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `secret not found`, + "not found": {"VAULT://secret___/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `secret not found`, func(t *testing.T) hashiVaultApi { return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() @@ -95,29 +119,64 @@ func TestVaultScenarios(t *testing.T) { return nil, fmt.Errorf("secret not found") }) }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, + }, + "403": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `client 403`, + func(t *testing.T) hashiVaultApi { + return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) + } + return nil, fmt.Errorf("client 403") + }) + }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, }, - "403": {"VAULT://secret/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `client 403`, func(t *testing.T) hashiVaultApi { + "found but empty": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{}`, func(t *testing.T) hashiVaultApi { return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) } - return nil, fmt.Errorf("client 403") + m := make(map[string]interface{}) + return &vault.KVSecret{Data: m}, nil }) }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, }, - "found but empty": {"VAULT://secret/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{}`, func(t *testing.T) hashiVaultApi { + "found but nil returned": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, "", func(t *testing.T) hashiVaultApi { return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { - t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) + t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) } - m := make(map[string]interface{}) - return &vault.KVSecret{Data: m}, nil + return &vault.KVSecret{Data: nil}, nil }) }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, }, - "found but nil returned": {"VAULT://secret/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, "", func(t *testing.T) hashiVaultApi { + "vault rate limit incorrect": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, "unable to initialize Vault client: error encountered setting up default configuration: VAULT_RATE_LIMIT was provided but incorrectly formatted", func(t *testing.T) hashiVaultApi { return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { @@ -126,15 +185,31 @@ func TestVaultScenarios(t *testing.T) { return &vault.KVSecret{Data: nil}, nil }) }, + func() func() { + os.Setenv("VAULT_TOKEN_INCORRECT", "") + os.Setenv("VAULT_ADDR", "wrong://addr") + os.Setenv("VAULT_RATE_LIMIT", "wrong") + // os.Setenv("AWS_ACCESS_KEY_ID", "1280qwed9u9nsc9fdsbv9gsfrd") + // os.Setenv("AWS_SECRET_ACCESS_KEY", "SED)SDVfdv0jfds08sdfgu09sd943tj4fELH/") + // os.Setenv("AWS_SESSION_TOKEN", "IQoJb3JpZ2luX2VjELH//////////wEaCWV1LXdlc3QtMiJIMEYCIQDPU6UGJ0...df.fdgdfg.dfg.gdf.dgf") + // os.Setenv("AWS_REGION", "eu-west-1") + return func() { + os.Clearenv() + } + }, }, } for name, tt := range ttests { t.Run(name, func(t *testing.T) { - os.Setenv("VAULT_TOKEN", "129378y1231283") - impl, err := NewVaultStore(context.TODO(), tt.token, tt.conf.tokenSeparator, tt.conf.keySeparator) + tearDown := tt.setupEnv() + defer tearDown() + impl, err := NewVaultStore(context.TODO(), tt.token, tt.conf) if err != nil { - t.Errorf("failed to init hashivault, %v", err) + if err.Error() != tt.expect { + t.Fatalf("failed to init hashivault, %v", err.Error()) + } + return } impl.svc = tt.mockClient(t) @@ -153,3 +228,22 @@ func TestVaultScenarios(t *testing.T) { }) } } + +func TestAwsIamAuth(t *testing.T) { + ttests := map[string]struct { + token string + conf GenVarsConfig + expect string + mockClient func(t *testing.T) hashiVaultApi + setupEnv func() func() + }{ + "test1": { + // objType: nil, + }, + } + for name, tt := range ttests { + t.Run(name, func(t *testing.T) { + _ = tt + }) + } +} diff --git a/pkg/generator/keyvault.go b/pkg/generator/keyvault.go index bbf3697..1619326 100644 --- a/pkg/generator/keyvault.go +++ b/pkg/generator/keyvault.go @@ -19,9 +19,10 @@ type kvApi interface { } type KvScrtStore struct { - svc kvApi - ctx context.Context - token string + svc kvApi + ctx context.Context + token string + config TokenConfigVars } // azVaultHelper provides a broken up string @@ -32,9 +33,17 @@ type azVaultHelper struct { // NewKvScrtStore returns a KvScrtStore // requires `AZURE_SUBSCRIPTION_ID` environment variable to be present to successfully work -func NewKvScrtStore(ctx context.Context, token, tokenSeparator, keySeparator string) (*KvScrtStore, error) { +func NewKvScrtStore(ctx context.Context, token string, conf GenVarsConfig) (*KvScrtStore, error) { - vc := azSplitToken(stripPrefix(token, AzKeyVaultSecretsPrefix, tokenSeparator, keySeparator)) + ct := conf.ParseTokenVars(token) + + kv := &KvScrtStore{ + ctx: ctx, + config: ct, + } + + vc := azSplitToken(stripPrefix(ct.Token, AzKeyVaultSecretsPrefix, conf.TokenSeparator(), conf.KeySeparator())) + kv.token = vc.token cred, err := azidentity.NewDefaultAzureCredential(nil) if err != nil { @@ -48,11 +57,9 @@ func NewKvScrtStore(ctx context.Context, token, tokenSeparator, keySeparator str return nil, err } - return &KvScrtStore{ - svc: c, - ctx: ctx, - token: vc.token, - }, nil + kv.svc = c + return kv, nil + } func (implmt *KvScrtStore) setToken(token string) { diff --git a/pkg/generator/keyvault_test.go b/pkg/generator/keyvault_test.go index 61d881f..0d47218 100644 --- a/pkg/generator/keyvault_test.go +++ b/pkg/generator/keyvault_test.go @@ -92,14 +92,12 @@ func (m mockAzKvSecretApi) GetSecret(ctx context.Context, name string, version s func Test_GetAzKeyVaultSecretVarHappy(t *testing.T) { tests := map[string]struct { - token string - keySeparator string - tokenSeparator string - expect string - mockClient func(t *testing.T) kvApi - config *GenVarsConfig + token string + expect string + mockClient func(t *testing.T) kvApi + config *GenVarsConfig }{ - "successVal": {"AZKVSECRET#/test-vault//token/1", "|", "#", tsuccessParam, func(t *testing.T) kvApi { + "successVal": {"AZKVSECRET#/test-vault//token/1", tsuccessParam, func(t *testing.T) kvApi { return mockAzKvSecretApi(func(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) { t.Helper() azKvCommonGetSecretChecker(t, name, "", "/token/1") @@ -107,9 +105,9 @@ func Test_GetAzKeyVaultSecretVarHappy(t *testing.T) { resp.Value = &tsuccessParam return resp, nil }) - }, NewConfig(), + }, NewConfig().WithKeySeparator("|").WithTokenSeparator("#"), }, - "successVal with keyseparator": {"AZKVSECRET#/test-vault/token/1|somekey", "|", "#", tsuccessParam, func(t *testing.T) kvApi { + "successVal with keyseparator": {"AZKVSECRET#/test-vault/token/1|somekey", tsuccessParam, func(t *testing.T) kvApi { return mockAzKvSecretApi(func(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) { t.Helper() azKvCommonGetSecretChecker(t, name, "", "token/1") @@ -119,9 +117,9 @@ func Test_GetAzKeyVaultSecretVarHappy(t *testing.T) { return resp, nil }) }, - NewConfig(), + NewConfig().WithKeySeparator("|").WithTokenSeparator("#"), }, - "errored": {"AZKVSECRET#/test-vault/token/1|somekey", "|", "#", "unable to retrieve secret", func(t *testing.T) kvApi { + "errored": {"AZKVSECRET#/test-vault/token/1|somekey", "unable to retrieve secret", func(t *testing.T) kvApi { return mockAzKvSecretApi(func(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) { t.Helper() azKvCommonGetSecretChecker(t, name, "", "token/1") @@ -130,9 +128,9 @@ func Test_GetAzKeyVaultSecretVarHappy(t *testing.T) { return resp, fmt.Errorf("unable to retrieve secret") }) }, - NewConfig(), + NewConfig().WithKeySeparator("|").WithTokenSeparator("#"), }, - "empty": {"AZKVSECRET#/test-vault/token/1|somekey", "|", "#", "", func(t *testing.T) kvApi { + "empty": {"AZKVSECRET#/test-vault/token/1|somekey", "", func(t *testing.T) kvApi { return mockAzKvSecretApi(func(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) { t.Helper() azKvCommonGetSecretChecker(t, name, "", "token/1") @@ -141,17 +139,17 @@ func Test_GetAzKeyVaultSecretVarHappy(t *testing.T) { return resp, nil }) }, - NewConfig(), + NewConfig().WithKeySeparator("|").WithTokenSeparator("#"), }, } for name, tt := range tests { t.Run(name, func(t *testing.T) { - impl, err := NewKvScrtStore(context.TODO(), tt.token, tt.tokenSeparator, tt.keySeparator) + impl, err := NewKvScrtStore(context.TODO(), tt.token, *tt.config) if err != nil { t.Errorf("failed to init azkvstore") } - tt.config.WithKeySeparator(tt.keySeparator).WithTokenSeparator(tt.tokenSeparator) + impl.svc = tt.mockClient(t) rs := newRetrieveStrategy(NewDefatultStrategy(), *tt.config) rs.setImplementation(impl) diff --git a/pkg/generator/secretsmanager.go b/pkg/generator/secretsmanager.go index 2eb0f30..68115ff 100644 --- a/pkg/generator/secretsmanager.go +++ b/pkg/generator/secretsmanager.go @@ -14,12 +14,13 @@ type secretsMgrApi interface { } type SecretsMgr struct { - svc secretsMgrApi - ctx context.Context - token string + svc secretsMgrApi + ctx context.Context + tokenConfig TokenConfigVars + token string } -func NewSecretsMgr(ctx context.Context) (*SecretsMgr, error) { +func NewSecretsMgr(ctx context.Context, conf GenVarsConfig) (*SecretsMgr, error) { cfg, err := config.LoadDefaultConfig(ctx) if err != nil { log.Errorf("unable to load SDK config, %v", err) @@ -34,6 +35,10 @@ func NewSecretsMgr(ctx context.Context) (*SecretsMgr, error) { } +// func(imp *SecretsMgr) getTokenConfig() AdditionalVars { +// return +// } + func (imp *SecretsMgr) setToken(token string) { imp.token = token } diff --git a/pkg/generator/secretsmanager_test.go b/pkg/generator/secretsmanager_test.go index 21149f7..fe98c4a 100644 --- a/pkg/generator/secretsmanager_test.go +++ b/pkg/generator/secretsmanager_test.go @@ -85,7 +85,7 @@ func Test_GetSecretMgr(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { tt.config.WithTokenSeparator(tt.tokenSeparator).WithKeySeparator(tt.keySeparator) - impl, _ := NewSecretsMgr(context.TODO()) + impl, _ := NewSecretsMgr(context.TODO(), *tt.config) impl.svc = tt.mockClient(t) rs := newRetrieveStrategy(NewDefatultStrategy(), *tt.config) diff --git a/pkg/generator/strategy.go b/pkg/generator/strategy.go index 5ef31cd..b65493b 100644 --- a/pkg/generator/strategy.go +++ b/pkg/generator/strategy.go @@ -18,6 +18,8 @@ func newRetrieveStrategy(s genVarsStrategy, config GenVarsConfig) *retrieveStrat } type genVarsStrategy interface { + // getTokenConfig() AdditionalVars + // setTokenConfig(AdditionalVars) getTokenValue(rs *retrieveStrategy) (s string, e error) setToken(s string) } @@ -51,18 +53,18 @@ func (rs *retrieveStrategy) RetrieveByToken(ctx context.Context, impl genVarsStr return cr } -func (rs *retrieveStrategy) SelectImplementation(ctx context.Context, prefix ImplementationPrefix, in string, config *GenVarsConfig) (genVarsStrategy, error) { +func (rs *retrieveStrategy) SelectImplementation(ctx context.Context, prefix ImplementationPrefix, in string, config GenVarsConfig) (genVarsStrategy, error) { switch prefix { case SecretMgrPrefix: - return NewSecretsMgr(ctx) + return NewSecretsMgr(ctx, config) case ParamStorePrefix: return NewParamStore(ctx) case AzKeyVaultSecretsPrefix: - return NewKvScrtStore(ctx, in, config.TokenSeparator(), config.KeySeparator()) + return NewKvScrtStore(ctx, in, config) case GcpSecretsPrefix: return NewGcpSecrets(ctx) case HashicorpVaultPrefix: - return NewVaultStore(ctx, in, config.TokenSeparator(), config.KeySeparator()) + return NewVaultStore(ctx, in, config) default: return nil, fmt.Errorf("implementation not found for input string: %s", in) } diff --git a/pkg/generator/strategy_test.go b/pkg/generator/strategy_test.go index 0c217df..fba8af3 100644 --- a/pkg/generator/strategy_test.go +++ b/pkg/generator/strategy_test.go @@ -88,7 +88,7 @@ func TestSelectImpl(t *testing.T) { prefix ImplementationPrefix in string config *GenVarsConfig - expect func(t *testing.T, ctx context.Context) genVarsStrategy + expect func(t *testing.T, ctx context.Context, conf GenVarsConfig) genVarsStrategy }{ "success AWSSEcretsMgr": { func() func() { @@ -99,8 +99,8 @@ func TestSelectImpl(t *testing.T) { }, context.TODO(), SecretMgrPrefix, "AWSSECRETS://foo/bar", (&GenVarsConfig{}).WithKeySeparator("|").WithTokenSeparator("://"), - func(t *testing.T, ctx context.Context) genVarsStrategy { - imp, err := NewSecretsMgr(ctx) + func(t *testing.T, ctx context.Context, conf GenVarsConfig) genVarsStrategy { + imp, err := NewSecretsMgr(ctx, conf) if err != nil { t.Errorf(testutils.TestPhraseWithContext, "aws secrets init impl error", err.Error(), nil) } @@ -116,7 +116,7 @@ func TestSelectImpl(t *testing.T) { }, context.TODO(), ParamStorePrefix, "AWSPARAMSTR://foo/bar", (&GenVarsConfig{}).WithKeySeparator("|").WithTokenSeparator("://"), - func(t *testing.T, ctx context.Context) genVarsStrategy { + func(t *testing.T, ctx context.Context, conf GenVarsConfig) genVarsStrategy { imp, err := NewParamStore(ctx) if err != nil { t.Errorf(testutils.TestPhraseWithContext, "paramstore init impl error", err.Error(), nil) @@ -136,7 +136,7 @@ func TestSelectImpl(t *testing.T) { }, context.TODO(), GcpSecretsPrefix, "GCPSECRETS://foo/bar", (&GenVarsConfig{}).WithKeySeparator("|").WithTokenSeparator("://"), - func(t *testing.T, ctx context.Context) genVarsStrategy { + func(t *testing.T, ctx context.Context, conf GenVarsConfig) genVarsStrategy { imp, err := NewGcpSecrets(ctx) if err != nil { t.Errorf(testutils.TestPhraseWithContext, "gcp secrets init impl error", err.Error(), nil) @@ -153,8 +153,8 @@ func TestSelectImpl(t *testing.T) { }, context.TODO(), AzKeyVaultSecretsPrefix, "AZKVSECRET://foo/bar", (&GenVarsConfig{}).WithKeySeparator("|").WithTokenSeparator("://"), - func(t *testing.T, ctx context.Context) genVarsStrategy { - imp, err := NewKvScrtStore(ctx, "AZKVSECRET://foo/bar", "://", "|") + func(t *testing.T, ctx context.Context, conf GenVarsConfig) genVarsStrategy { + imp, err := NewKvScrtStore(ctx, "AZKVSECRET://foo/bar", conf) if err != nil { t.Errorf(testutils.TestPhraseWithContext, "azkv init impl error", err.Error(), nil) } @@ -171,8 +171,8 @@ func TestSelectImpl(t *testing.T) { }, context.TODO(), HashicorpVaultPrefix, "VAULT://foo/bar", (&GenVarsConfig{}).WithKeySeparator("|").WithTokenSeparator("://"), - func(t *testing.T, ctx context.Context) genVarsStrategy { - imp, err := NewVaultStore(ctx, "VAULT://foo/bar", "://", "|") + func(t *testing.T, ctx context.Context, conf GenVarsConfig) genVarsStrategy { + imp, err := NewVaultStore(ctx, "VAULT://foo/bar", conf) if err != nil { t.Errorf(testutils.TestPhraseWithContext, "vault init impl error", err.Error(), nil) } @@ -188,7 +188,7 @@ func TestSelectImpl(t *testing.T) { }, context.TODO(), UnknownPrefix, "AWSPARAMSTR://foo/bar", (&GenVarsConfig{}).WithKeySeparator("|").WithTokenSeparator("://"), - func(t *testing.T, ctx context.Context) genVarsStrategy { + func(t *testing.T, ctx context.Context, conf GenVarsConfig) genVarsStrategy { imp, err := NewParamStore(ctx) if err != nil { t.Errorf(testutils.TestPhraseWithContext, "init impl error", err.Error(), nil) @@ -202,8 +202,8 @@ func TestSelectImpl(t *testing.T) { tearDown := tt.setUpTearDown() defer tearDown() rs := &retrieveStrategy{} - want := tt.expect(t, tt.ctx) - got, err := rs.SelectImplementation(tt.ctx, tt.prefix, tt.in, tt.config) + want := tt.expect(t, tt.ctx, *tt.config) + got, err := rs.SelectImplementation(tt.ctx, tt.prefix, tt.in, *tt.config) if err != nil { if err.Error() != fmt.Sprintf("implementation not found for input string: %s", tt.in) { t.Errorf(testutils.TestPhraseWithContext, "uncaught error", err.Error(), fmt.Sprintf("implementation not found for input string: %s", tt.in)) From 1d6933a65f03fdedf4812e5018088f1fc412e97b Mon Sep 17 00:00:00 2001 From: dnitsch Date: Thu, 9 Feb 2023 14:58:52 +0000 Subject: [PATCH 4/6] fix: hashivault tests and implementation --- pkg/generator/config.go | 2 +- pkg/generator/config_test.go | 2 +- pkg/generator/hashivault.go | 15 ++++- pkg/generator/hashivault_test.go | 97 ++++++++++++++++++++++++++------ 4 files changed, 95 insertions(+), 21 deletions(-) diff --git a/pkg/generator/config.go b/pkg/generator/config.go index 48544dc..5ac30e4 100644 --- a/pkg/generator/config.go +++ b/pkg/generator/config.go @@ -71,7 +71,7 @@ func (c *GenVarsConfig) KeySeparator() string { func (c GenVarsConfig) ParseTokenVars(token string) TokenConfigVars { tc := TokenConfigVars{} // strip anything in [] - vars := regexp.MustCompile(`\[.+\]`) + vars := regexp.MustCompile(`\[.*\]`) rawVars := vars.FindString(token) // extract [role:,version:] if rawVars != "" { diff --git a/pkg/generator/config_test.go b/pkg/generator/config_test.go index d32d9ff..735c302 100644 --- a/pkg/generator/config_test.go +++ b/pkg/generator/config_test.go @@ -60,7 +60,7 @@ func TestParseTokens(t *testing.T) { }, "additional config specified but empty": { *generator.NewConfig(), - `FOO://basjh/dskjuds/123`, + `FOO://basjh/dskjuds/123[]`, generator.TokenConfigVars{ Token: `FOO://basjh/dskjuds/123`, Role: ``, diff --git a/pkg/generator/hashivault.go b/pkg/generator/hashivault.go index fdfd558..2eea20f 100644 --- a/pkg/generator/hashivault.go +++ b/pkg/generator/hashivault.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "strconv" "strings" "github.com/dnitsch/configmanager/pkg/log" @@ -21,6 +22,7 @@ type vaultHelper struct { type hashiVaultApi interface { Get(ctx context.Context, secretPath string) (*vault.KVSecret, error) + GetVersion(ctx context.Context, secretPath string, version int) (*vault.KVSecret, error) } type VaultStore struct { @@ -106,7 +108,7 @@ func (imp *VaultStore) getTokenValue(v *retrieveStrategy) (string, error) { ctx, cancel := context.WithCancel(imp.ctx) defer cancel() - secret, err := imp.svc.Get(ctx, v.stripPrefix(imp.token, HashicorpVaultPrefix)) + secret, err := imp.getSecret(ctx, v.stripPrefix(imp.token, HashicorpVaultPrefix), imp.config.Version) if err != nil { log.Errorf(implementationNetworkErr, HashicorpVaultPrefix, err, imp.token) return "", err @@ -126,6 +128,17 @@ func (imp *VaultStore) getTokenValue(v *retrieveStrategy) (string, error) { return "", nil } +func (imp *VaultStore) getSecret(ctx context.Context, token string, version string) (*vault.KVSecret, error) { + if version != "" { + v, err := strconv.Atoi(version) + if err != nil { + return nil, fmt.Errorf("unable to parse version into an integer: %s", err.Error()) + } + return imp.svc.GetVersion(ctx, token, v) + } + return imp.svc.Get(ctx, token) +} + func splitToken(token string) vaultHelper { vh := vaultHelper{} // split token to extract the mount path diff --git a/pkg/generator/hashivault_test.go b/pkg/generator/hashivault_test.go index c405584..01e7aaf 100644 --- a/pkg/generator/hashivault_test.go +++ b/pkg/generator/hashivault_test.go @@ -34,10 +34,17 @@ func TestMountPathExtract(t *testing.T) { } } -type mockVaultApi func(ctx context.Context, secretPath string) (*vault.KVSecret, error) +type mockVaultApi struct { + g func(ctx context.Context, secretPath string) (*vault.KVSecret, error) + gv func(ctx context.Context, secretPath string, version int) (*vault.KVSecret, error) +} func (m mockVaultApi) Get(ctx context.Context, secretPath string) (*vault.KVSecret, error) { - return m(ctx, secretPath) + return m.g(ctx, secretPath) +} + +func (m mockVaultApi) GetVersion(ctx context.Context, secretPath string, version int) (*vault.KVSecret, error) { + return m.gv(ctx, secretPath, version) } func TestVaultScenarios(t *testing.T) { @@ -50,7 +57,8 @@ func TestVaultScenarios(t *testing.T) { }{ "happy return": {"VAULT://secret___/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{"foo":"test2130-9sd-0ds"}`, func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "foo" { t.Errorf("got %v; want %s", secretPath, `foo`) @@ -58,7 +66,8 @@ func TestVaultScenarios(t *testing.T) { m := make(map[string]interface{}) m["foo"] = "test2130-9sd-0ds" return &vault.KVSecret{Data: m}, nil - }) + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN", "129378y1231283") @@ -69,7 +78,8 @@ func TestVaultScenarios(t *testing.T) { }, "incorrect json": {"VAULT://secret___/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `json: unsupported type: func() error`, func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "foo" { t.Errorf("got %v; want %s", secretPath, `foo`) @@ -77,7 +87,8 @@ func TestVaultScenarios(t *testing.T) { m := make(map[string]interface{}) m["error"] = func() error { return fmt.Errorf("ddodod") } return &vault.KVSecret{Data: m}, nil - }) + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN", "129378y1231283") @@ -91,7 +102,8 @@ func TestVaultScenarios(t *testing.T) { GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{"foo1":"test2130-9sd-0ds","foo2":"dsfsdf3454456"}`, func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) @@ -100,7 +112,8 @@ func TestVaultScenarios(t *testing.T) { m["foo1"] = "test2130-9sd-0ds" m["foo2"] = "dsfsdf3454456" return &vault.KVSecret{Data: m}, nil - }) + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN", "129378y1231283") @@ -111,13 +124,15 @@ func TestVaultScenarios(t *testing.T) { }, "not found": {"VAULT://secret___/foo", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `secret not found`, func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "foo" { t.Errorf("got %v; want %s", secretPath, `foo`) } return nil, fmt.Errorf("secret not found") - }) + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN", "129378y1231283") @@ -128,13 +143,15 @@ func TestVaultScenarios(t *testing.T) { }, "403": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `client 403`, func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) } return nil, fmt.Errorf("client 403") - }) + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN", "129378y1231283") @@ -144,14 +161,16 @@ func TestVaultScenarios(t *testing.T) { }, }, "found but empty": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{}`, func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { t.Errorf("got %v; want %s", secretPath, `some/other/foo2`) } m := make(map[string]interface{}) return &vault.KVSecret{Data: m}, nil - }) + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN", "129378y1231283") @@ -161,13 +180,53 @@ func TestVaultScenarios(t *testing.T) { }, }, "found but nil returned": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, "", func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) } return &vault.KVSecret{Data: nil}, nil - }) + } + return mv + }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, + }, + "version provided correctly": {"VAULT://secret___/some/other/foo2[version:1]", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, `{"foo2":"dsfsdf3454456"}`, func(t *testing.T) hashiVaultApi { + mv := mockVaultApi{} + mv.gv = func(ctx context.Context, secretPath string, version int) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) + } + m := make(map[string]interface{}) + m["foo2"] = "dsfsdf3454456" + return &vault.KVSecret{Data: m}, nil + } + return mv + }, + func() func() { + os.Setenv("VAULT_TOKEN", "129378y1231283") + return func() { + os.Clearenv() + } + }, + }, + "version provided but unable to parse": {"VAULT://secret___/some/other/foo2[version:1a]", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, "unable to parse version into an integer: strconv.Atoi: parsing \"1a\": invalid syntax", func(t *testing.T) hashiVaultApi { + mv := mockVaultApi{} + mv.gv = func(ctx context.Context, secretPath string, version int) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) + } + return nil, nil + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN", "129378y1231283") @@ -177,13 +236,15 @@ func TestVaultScenarios(t *testing.T) { }, }, "vault rate limit incorrect": {"VAULT://secret___/some/other/foo2", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, "unable to initialize Vault client: error encountered setting up default configuration: VAULT_RATE_LIMIT was provided but incorrectly formatted", func(t *testing.T) hashiVaultApi { - return mockVaultApi(func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { t.Helper() if secretPath != "some/other/foo2" { t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) } return &vault.KVSecret{Data: nil}, nil - }) + } + return mv }, func() func() { os.Setenv("VAULT_TOKEN_INCORRECT", "") From 44feca3c24cf52ca6caf488459763a748908c2e3 Mon Sep 17 00:00:00 2001 From: dnitsch Date: Thu, 9 Feb 2023 15:59:40 +0000 Subject: [PATCH 5/6] fix: add more tests to hashivault --- internal/testutils/testutils.go | 4 +- pkg/generator/hashivault.go | 2 +- pkg/generator/hashivault_test.go | 194 ++++++++++++++++++++++++++++--- 3 files changed, 183 insertions(+), 17 deletions(-) diff --git a/internal/testutils/testutils.go b/internal/testutils/testutils.go index b9ba4a2..767f95c 100644 --- a/internal/testutils/testutils.go +++ b/internal/testutils/testutils.go @@ -1,6 +1,6 @@ package testutils const ( - TestPhrase string = "got: %v want: %v\n" - TestPhraseWithContext string = "%s got: %v want: %v\n" + TestPhrase string = "got: %v want: %v\n" + TestPhraseWithContext string = "%s\n got: %v\n\n want: %v\n" ) diff --git a/pkg/generator/hashivault.go b/pkg/generator/hashivault.go index 2eea20f..fa56448 100644 --- a/pkg/generator/hashivault.go +++ b/pkg/generator/hashivault.go @@ -54,7 +54,7 @@ func NewVaultStore(ctx context.Context, token string, conf GenVarsConfig) (*Vaul } if strings.HasPrefix(os.Getenv("VAULT_TOKEN"), "aws_iam") { - awsclient, err := newVaultStoreWithAWSAuthIAM(client, conf.ParseTokenVars(token).Role) + awsclient, err := newVaultStoreWithAWSAuthIAM(client, tc.Role) if err != nil { return nil, err } diff --git a/pkg/generator/hashivault_test.go b/pkg/generator/hashivault_test.go index 01e7aaf..731248e 100644 --- a/pkg/generator/hashivault_test.go +++ b/pkg/generator/hashivault_test.go @@ -3,7 +3,10 @@ package generator import ( "context" "fmt" + "net/http" + "net/http/httptest" "os" + "strings" "testing" "github.com/dnitsch/configmanager/internal/testutils" @@ -247,13 +250,8 @@ func TestVaultScenarios(t *testing.T) { return mv }, func() func() { - os.Setenv("VAULT_TOKEN_INCORRECT", "") - os.Setenv("VAULT_ADDR", "wrong://addr") + os.Setenv("VAULT_TOKEN", "") os.Setenv("VAULT_RATE_LIMIT", "wrong") - // os.Setenv("AWS_ACCESS_KEY_ID", "1280qwed9u9nsc9fdsbv9gsfrd") - // os.Setenv("AWS_SECRET_ACCESS_KEY", "SED)SDVfdv0jfds08sdfgu09sd943tj4fELH/") - // os.Setenv("AWS_SESSION_TOKEN", "IQoJb3JpZ2luX2VjELH//////////wEaCWV1LXdlc3QtMiJIMEYCIQDPU6UGJ0...df.fdgdfg.dfg.gdf.dgf") - // os.Setenv("AWS_REGION", "eu-west-1") return func() { os.Clearenv() } @@ -292,19 +290,187 @@ func TestVaultScenarios(t *testing.T) { func TestAwsIamAuth(t *testing.T) { ttests := map[string]struct { - token string - conf GenVarsConfig - expect string - mockClient func(t *testing.T) hashiVaultApi - setupEnv func() func() + token string + conf GenVarsConfig + expect string + mockClient func(t *testing.T) hashiVaultApi + mockHanlder func(t *testing.T) http.Handler + setupEnv func(addr string) func() }{ - "test1": { - // objType: nil, + "aws_iam auth no role specified": { + "VAULT://secret___/some/other/foo2[version:1]", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, + "role provided is empty, EC2 auth not supported", + func(t *testing.T) hashiVaultApi { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) + } + return &vault.KVSecret{Data: nil}, nil + } + return mv + }, + func(t *testing.T) http.Handler { + return nil + }, + func(_ string) func() { + os.Setenv("VAULT_TOKEN", "aws_iam") + os.Setenv("AWS_ACCESS_KEY_ID", "1280qwed9u9nsc9fdsbv9gsfrd") + os.Setenv("AWS_SECRET_ACCESS_KEY", "SED)SDVfdv0jfds08sdfgu09sd943tj4fELH/") + os.Setenv("AWS_SESSION_TOKEN", "IQoJb3JpZ2luX2VjELH//////////wEaCWV1LXdlc3QtMiJIMEYCIQDPU6UGJ0...df.fdgdfg.dfg.gdf.dgf") + os.Setenv("AWS_REGION", "eu-west-1") + return func() { + os.Clearenv() + } + }, + }, + "aws_iam auth incorrectly formatted request": { + "VAULT://secret___/some/other/foo2[version:1,role:not_a_role]", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, + `unable to login to AWS auth method: unable to log in to auth method: unable to log in with AWS auth: Error making API request. + +URL: PUT %s/v1/auth/aws/login +Code: 400. Raw Message: + +incorrect values supplied`, + func(t *testing.T) hashiVaultApi { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) + } + return &vault.KVSecret{Data: nil}, nil + } + return mv + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/v1/auth/aws/login", func(w http.ResponseWriter, r *http.Request) { + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(400) + w.Write([]byte(`incorrect values supplied`)) + }) + return mux + }, + func(addr string) func() { + os.Setenv("VAULT_TOKEN", "aws_iam") + os.Setenv("VAULT_ADDR", addr) + os.Setenv("AWS_ACCESS_KEY_ID", "1280qwed9u9nsc9fdsbv9gsfrd") + os.Setenv("AWS_SECRET_ACCESS_KEY", "SED)SDVfdv0jfds08sdfgu09sd943tj4fELH/") + os.Setenv("AWS_SESSION_TOKEN", "IQoJb3JpZ2luX2VjELH//////////wEaCWV1LXdlc3QtMiJIMEYCIQDPU6UGJ0...df.fdgdfg.dfg.gdf.dgf") + os.Setenv("AWS_REGION", "eu-west-1") + return func() { + os.Clearenv() + } + }, + }, + "aws_iam auth success": { + "VAULT://secret___/some/other/foo2[role:arn:aws:iam::1111111:role/i-orchestration]", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, + `{"foo2":"dsfsdf3454456"}`, + func(t *testing.T) hashiVaultApi { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) + } + m := make(map[string]interface{}) + m["foo2"] = "dsfsdf3454456" + return &vault.KVSecret{Data: m}, nil + } + return mv + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/v1/auth/aws/login", func(w http.ResponseWriter, r *http.Request) { + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Write([]byte(`{"auth":{"client_token": "fooresddfasdsasad"}}`)) + }) + return mux + }, + func(addr string) func() { + os.Setenv("VAULT_TOKEN", "aws_iam") + os.Setenv("VAULT_ADDR", addr) + os.Setenv("AWS_ACCESS_KEY_ID", "1280qwed9u9nsc9fdsbv9gsfrd") + os.Setenv("AWS_SECRET_ACCESS_KEY", "SED)SDVfdv0jfds08sdfgu09sd943tj4fELH/") + os.Setenv("AWS_SESSION_TOKEN", "IQoJb3JpZ2luX2VjELH//////////wEaCWV1LXdlc3QtMiJIMEYCIQDPU6UGJ0...df.fdgdfg.dfg.gdf.dgf") + os.Setenv("AWS_REGION", "eu-west-1") + return func() { + os.Clearenv() + } + }, + }, + "aws_iam auth no token returned": { + "VAULT://secret___/some/other/foo2[role:arn:aws:iam::1111111:role/i-orchestration]", GenVarsConfig{tokenSeparator: "://", keySeparator: "|"}, + `unable to login to AWS auth method: response did not return ClientToken, client token not set`, + func(t *testing.T) hashiVaultApi { + mv := mockVaultApi{} + mv.g = func(ctx context.Context, secretPath string) (*vault.KVSecret, error) { + t.Helper() + if secretPath != "some/other/foo2" { + t.Errorf(testutils.TestPhrase, secretPath, `some/other/foo2`) + } + m := make(map[string]interface{}) + m["foo2"] = "dsfsdf3454456" + return &vault.KVSecret{Data: m}, nil + } + return mv + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/v1/auth/aws/login", func(w http.ResponseWriter, r *http.Request) { + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Write([]byte(`{"auth":{}}`)) + }) + return mux + }, + func(addr string) func() { + os.Setenv("VAULT_TOKEN", "aws_iam") + os.Setenv("VAULT_ADDR", addr) + os.Setenv("AWS_ACCESS_KEY_ID", "1280qwed9u9nsc9fdsbv9gsfrd") + os.Setenv("AWS_SECRET_ACCESS_KEY", "SED)SDVfdv0jfds08sdfgu09sd943tj4fELH/") + os.Setenv("AWS_SESSION_TOKEN", "IQoJb3JpZ2luX2VjELH//////////wEaCWV1LXdlc3QtMiJIMEYCIQDPU6UGJ0...df.fdgdfg.dfg.gdf.dgf") + os.Setenv("AWS_REGION", "eu-west-1") + return func() { + os.Clearenv() + } + }, }, } + for name, tt := range ttests { t.Run(name, func(t *testing.T) { - _ = tt + // + ts := httptest.NewServer(tt.mockHanlder(t)) + tearDown := tt.setupEnv(ts.URL) + defer tearDown() + impl, err := NewVaultStore(context.TODO(), tt.token, tt.conf) + if err != nil { + // WHAT A CRAP way to do this... + if err.Error() != strings.Split(fmt.Sprintf(tt.expect, ts.URL), `%!`)[0] { + t.Errorf(testutils.TestPhraseWithContext, "aws iam auth", err.Error(), strings.Split(fmt.Sprintf(tt.expect, ts.URL), `%!`)[0]) + t.Fatalf("failed to init hashivault, %v", err.Error()) + } + return + } + + impl.svc = tt.mockClient(t) + rs := newRetrieveStrategy(NewDefatultStrategy(), tt.conf) + rs.setImplementation(impl) + got, err := rs.getTokenValue() + if err != nil { + if err.Error() != tt.expect { + t.Errorf(testutils.TestPhrase, err.Error(), tt.expect) + } + return + } + if got != tt.expect { + t.Errorf(testutils.TestPhrase, got, tt.expect) + } }) } } From 1be498ffa87f4a463b717f2676c73b90375ed7ca Mon Sep 17 00:00:00 2001 From: dnitsch Date: Thu, 9 Feb 2023 16:47:51 +0000 Subject: [PATCH 6/6] fix: add docs to document additional hashicorp features --- README.md | 54 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6a1d38d..e65c913 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,32 @@ Package used for retrieving application settings from various sources. Currently supported variable and secrets implementations: + - [AWS SecretsManager](https://aws.amazon.com/secrets-manager/) + - Implementation Indicator: `AWSSECRETS` - [AWS ParameterStore](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) + - Implementation Indicator: `AWSPARAMSTR` - [AzureKeyvault Secrets](https://azure.microsoft.com/en-gb/products/key-vault/) + - Implementation Indicator: `AZKVSECRET` - see [Special consideration for AZKVSECRET](#special-consideration-for-azkvsecret) around how to structure the token in this case. - [GCP Secrets](https://cloud.google.com/secret-manager) + - Implementation Indicator: `GCPSECRETS` - [Hashicorp Vault](https://developer.hashicorp.com/vault/docs/secrets/kv) - - using the V2 endpoint + - Implementation Indicator: `VAULT` + - using the KvV2 engine endpoint - see [special consideration hashivault](#special-consideration-for-hashicorpvault) -The main driver is to use component level configuration objects, if stored in a `"namespaced"` manner e.g. in AWS ParamStore as `/nonprod/component-service-a/configVar`, however this is not a requirement and the param name can be whatever. Though whilst using some sort of a organised manner it will be more straight forward to allow other services to consume certain secrets/params based on resource/access policies. +The main driver is to use component level configuration objects, if stored in a `"namespaced"` manner e.g. in AWS ParamStore as `/nonprod/component-service-a/configVar`, however this is not a requirement and the param name can be whatever. Though whilst using some sort of a organised manner it will be more straight forward to allow other services to consume certain secrets/params based on resource/access policies. > Beware size limitation with certain config/vault implementations. In which case it's best to split certain items up e.g. TLS certs `/nonprod/component-service-a/pub-cert`, `/nonprod/component-service-a/private-cert`, `/nonprod/component-service-a/chain1-cert`, etc... @@ -46,13 +61,17 @@ ConfigManager comes packaged as a CLI for all major platforms, to see [download/ For more detailed usage you can run -h with each subcommand and additional info can be found [here](./docs/commands.md) -## Config Tokens +## __Config Tokens__ The token is made up of 3 parts: -- `AWSSECRETS` the strategy identifier to choose at runtime +### Implementation indicator -- `#` separator - used for separating the implementation indicator and the look up value. +e.g. `AWSSECRETS` the strategy identifier to choose at runtime + +### __Token Separator__ + +e.g. `#` - used for separating the implementation indicator and the look up value. > The default is currently `#` - it will change to `://` to allow for a more natural reading of the "token". you can achieve this behaviour now by either specifying the `-s` to the CLI or ConfigManager public methods, like below. @@ -72,11 +91,12 @@ Alternatively you can use the helper methods for Yaml or Json tagged structs - s If contents of the `AWSSECRETS#/appxyz/service1-password` are a string then `service1-password` will be the key and converted to UPPERCASE e.g. `SERVICE1_PASSWORD=som3V4lue` -### KeySeparator +### __Key Separator__ Specifying a key seperator on token items that can be parsed as a K/V map will result in only retrieving the specific key from the map. e.g. if contents of the `AWSSECRETS#/appxyz/service1-db-config` are parseable into the below object + ```json { "host": "db.internal", @@ -113,7 +133,6 @@ db: If your config parameter matches the config interface, you can also leave the entire token to point to the `db` key - ```yaml app: name: xyz @@ -132,6 +151,20 @@ db: { } ``` +### Additional Token Config + +Suffixed `[]` with `role:` or `version:` specified inside the brackets and comma separated + +order is not important, but the `role:` keyword must be followed by the role string + +e.g. `VAULT://baz/bar/123|d88[role:arn:aws:iam::1111111:role/i-orchestration,version:1082313]` + +Currently only supporting version and role but may be extended in the future. + +- role is used with `VAULT` `aws_iam` auth type. Specifying it on a token level as opposed to globally will ensure that multiple roles can be used provided that the caller has the ability to assume them. + +- version can be used within all implementations that support versioned config items e.g. `VAULT`, `GCPSECRETS` , `AWSSECRETS`, `AZKVSECRET`. If omitted it will default to the `LATEST`. + ### Special consideration for AZKVSECRET For Azure KeyVault the first part of the token needs to be the name of the vault. @@ -147,12 +180,15 @@ For Azure KeyVault the first part of the token needs to be the name of the vault ### Special consideration for HashicorpVault For HashicorpVault the first part of the token needs to be the name of the mountpath. In Dev Vaults this is `"secret"`, - e.g.: + e.g.: `VAULT://secret___demo/configmanager|test` -`VAULT://secret___demo/configmanager|test` +or if the secrets are at another location: `VAULT://another/mount/path__config/app1/db` The hardcoded separator cannot be modified and you must separate your `mountPath` with `___` (3x `_`) followed by the key to the secret. +#### AWS IAM auth to vault + +when using Vault in AWS - you can set the value of the `VAULT_TOKEN=aws_iam` this will trigger the AWS Auth login as opposed to using the local token. The Hashicorp Vault functions in the same exact way as the other implementations. It will retrieve the JSON object and can be looked up within it by using a key separator.