diff --git a/CHANGELOG.md b/CHANGELOG.md index c925588..02c35bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## Unreleased +IMPROVEMENTS: + +* Migrated AWS provider dependency from `aws-sdk-go` (v1) to `aws-sdk-go-v2` for improved performance and maintainability. (https://github.com/hashicorp/vault-lambda-extension/pull/191) +* Bumped versions for the following dependencies: + * github.com/fatih/color v1.19.0 + * github.com/mattn/go-colorable v0.1.14 + * golang.org/x/sys v0.42.0 + ## 0.14.0 (Mar 10, 2026) LAYERS: diff --git a/go.mod b/go.mod index 4226c44..75ebfd9 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,11 @@ module github.com/hashicorp/vault-lambda-extension go 1.25.7 require ( - github.com/aws/aws-sdk-go v1.55.6 + github.com/aws/aws-sdk-go-v2 v1.41.5 + github.com/aws/aws-sdk-go-v2/config v1.32.13 + github.com/aws/aws-sdk-go-v2/credentials v1.19.13 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 + github.com/aws/smithy-go v1.24.2 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/vault/api v1.15.0 @@ -13,9 +17,18 @@ require ( ) require ( + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/fatih/color v1.17.0 // indirect + github.com/fatih/color v1.19.0 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -27,8 +40,8 @@ require ( github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.6 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -38,8 +51,9 @@ require ( github.com/sasha-s/go-deadlock v0.3.5 // indirect golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index aaf0853..530548a 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,41 @@ -github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk= -github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= +github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2/config v1.32.13 h1:5KgbxMaS2coSWRrx9TX/QtWbqzgQkOdEa3sZPhBhCSg= +github.com/aws/aws-sdk-go-v2/config v1.32.13/go.mod h1:8zz7wedqtCbw5e9Mi2doEwDyEgHcEE9YOJp6a8jdSMY= +github.com/aws/aws-sdk-go-v2/credentials v1.19.13 h1:mA59E3fokBvyEGHKFdnpNNrvaR351cqiHgRg+JzOSRI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.13/go.mod h1:yoTXOQKea18nrM69wGF9jBdG4WocSZA1h38A+t/MAsk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 h1:GcLE9ba5ehAQma6wlopUesYg/hbcOhFNWTjELkiWkh4= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.14/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 h1:mP49nTpfKtpXLt5SLn8Uv8z6W+03jYVoOSAl/c02nog= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw= +github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= +github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -44,17 +71,19 @@ github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/ github.com/hashicorp/vault/api v1.15.0/go.mod h1:+5YTO09JGn0u+b6ySD/LLVf8WkJCPLAL2Vkmrn2+CM8= github.com/hashicorp/vault/sdk v0.15.0 h1:xNo1lL2shm0yE4coXNZkTV/6++2GfEh+/cCAfBjzEnA= github.com/hashicorp/vault/sdk v0.15.0/go.mod h1:2Wj2tHIgfz0gNWgEPWBbCXFIiPrq96E8FTjPNV9J1Bc= -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= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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/mattn/go-colorable v0.1.9/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-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -68,6 +97,9 @@ github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7c github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= @@ -86,18 +118,17 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w 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-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/proxy/proxy_test.go b/internal/proxy/proxy_test.go index b73a211..3f0cdcc 100644 --- a/internal/proxy/proxy_test.go +++ b/internal/proxy/proxy_test.go @@ -4,6 +4,7 @@ package proxy import ( + "context" "encoding/json" "errors" "fmt" @@ -14,12 +15,14 @@ import ( "strings" "testing" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" + awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/hashicorp/go-hclog" - "github.com/hashicorp/vault-lambda-extension/internal/config" + internalconfig "github.com/hashicorp/vault-lambda-extension/internal/config" "github.com/hashicorp/vault-lambda-extension/internal/ststest" "github.com/hashicorp/vault-lambda-extension/internal/vault" "github.com/hashicorp/vault/api" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -63,11 +66,12 @@ var ( func TestProxy(t *testing.T) { fakeVault := fakeVault() defer fakeVault.Close() - ses := session.Must(session.NewSession()) - sts := ststest.FakeSTS(ses) - defer sts.Close() - proxyAddr, close := startProxy(t, fakeVault.URL, ses) - defer close() + awsCfg, err := awsconfig.LoadDefaultConfig(context.Background()) + require.NoError(t, err, "failed to load AWS config ") + fakeSTS, awsCfg := ststest.FakeSTS(&awsCfg) + defer fakeSTS.Close() + proxyAddr, cleanup := startProxy(t, fakeVault.URL, awsCfg) + defer cleanup() t.Run("happy path bare http client", func(t *testing.T) { // reset request array @@ -77,7 +81,9 @@ func TestProxy(t *testing.T) { // the stored request should be the one _from the proxy_ since it's stored by // the (fake) vault. - require.Contains(t, vaultRequests[1].Header.Get("User-Agent"), proxyUserAgent) + require.Len(t, vaultRequests, 2) + assert.Contains(t, vaultRequests[0].URL.Path, "login") + assert.Contains(t, vaultRequests[1].Header.Get("User-Agent"), proxyUserAgent) require.NoError(t, err) require.Equal(t, http.StatusOK, resp.StatusCode) defer resp.Body.Close() @@ -134,7 +140,9 @@ func TestProxy(t *testing.T) { // the stored request should be the one _from the proxy_ since it's stored by // the (fake) vault. // revoke should trigger another login call, and still get the secret + require.Len(t, vaultRequests, 2) require.Contains(t, vaultRequests[0].URL.Path, "login") + require.Contains(t, vaultRequests[1].Header.Get("User-Agent"), proxyUserAgent) require.NoError(t, err) require.Equal(t, http.StatusOK, resp.StatusCode) defer resp.Body.Close() @@ -146,16 +154,20 @@ func TestProxy(t *testing.T) { }) } -func startProxy(t *testing.T, vaultAddress string, ses *session.Session) (string, func() error) { +func startProxy(t *testing.T, vaultAddress string, awsCfg aws.Config) (string, func() error) { vaultConfig := api.DefaultConfig() require.NoError(t, vaultConfig.Error) vaultConfig.Address = vaultAddress - client, err := vault.NewClient("", "", hclog.NewNullLogger(), vaultConfig, config.AuthConfig{}, ses) + authConfig := internalconfig.AuthConfig{ + Provider: "aws", + Role: "test-role", + } + client, err := vault.NewClient("", "", hclog.NewNullLogger(), vaultConfig, authConfig, awsCfg) require.NoError(t, err) client.VaultConfig.Address = vaultAddress ln, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) - proxy := New(hclog.NewNullLogger(), client, config.CacheConfig{}) + proxy := New(hclog.NewNullLogger(), client, internalconfig.CacheConfig{}) go func() { _ = proxy.Serve(ln) }() diff --git a/internal/ststest/sts.go b/internal/ststest/sts.go index 8a6482d..c304e3d 100644 --- a/internal/ststest/sts.go +++ b/internal/ststest/sts.go @@ -7,26 +7,21 @@ import ( "net/http" "net/http/httptest" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/credentials" ) -// FakeSTS creates a fake STS server, and configures the session passed in +// FakeSTS creates a fake STS server, and configures the AWS config passed in // to talk to that server. -func FakeSTS(ses *session.Session) *httptest.Server { +func FakeSTS(cfg *aws.Config) (*httptest.Server, aws.Config) { + cpycfg := *cfg stsServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) })) - ses.Config. - WithEndpoint(stsServer.URL). - WithRegion("us-east-1"). - WithCredentials(credentials.NewStaticCredentialsFromCreds(credentials.Value{ - ProviderName: session.EnvProviderName, - AccessKeyID: "foo", - SecretAccessKey: "foo", - SessionToken: "foo", - })) + cpycfg.BaseEndpoint = aws.String(stsServer.URL) + cpycfg.Region = "us-east-1" + cpycfg.Credentials = aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider("foo", "foo", "foo")) - return stsServer + return stsServer, cpycfg } diff --git a/internal/vault/client.go b/internal/vault/client.go index 56da7b0..c165fd5 100644 --- a/internal/vault/client.go +++ b/internal/vault/client.go @@ -5,21 +5,20 @@ package vault import ( "context" + "crypto/sha256" "encoding/base64" "encoding/json" "fmt" - "io" + "net/http" "os" "strings" "sync" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/endpoints" - - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/sts" + "github.com/aws/aws-sdk-go-v2/aws" + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/api" @@ -29,6 +28,7 @@ import ( const ( tokenExpiryGracePeriodEnv = "VAULT_TOKEN_EXPIRY_GRACE_PERIOD" defaultTokenExpiryGracePeriod = 10 * time.Second + defaultSTSRegion = "us-east-1" ) // Client holds api.Client and handles state required to renew tokens and re-auth as required. @@ -42,7 +42,7 @@ type Client struct { VaultConfig *api.Config logger hclog.Logger - stsSvc *sts.STS + awsCfg aws.Config authConfig config.AuthConfig // Token refresh/renew data. @@ -55,7 +55,7 @@ type Client struct { // NewClient uses the AWS IAM auth method configured in a Vault cluster to // authenticate the execution role and create a Vault API client. -func NewClient(name, version string, logger hclog.Logger, vaultConfig *api.Config, authConfig config.AuthConfig, awsSes *session.Session) (*Client, error) { +func NewClient(name, version string, logger hclog.Logger, vaultConfig *api.Config, authConfig config.AuthConfig, awsCfg aws.Config) (*Client, error) { vaultClient, err := api.NewClient(vaultConfig) if err != nil { return nil, fmt.Errorf("error making extension: %w", err) @@ -73,7 +73,7 @@ func NewClient(name, version string, logger hclog.Logger, vaultConfig *api.Confi Version: version, logger: logger, - stsSvc: sts.New(awsSes), + awsCfg: awsCfg, authConfig: authConfig, tokenExpiryGracePeriod: expiryGracePeriod, @@ -115,10 +115,10 @@ func (c *Client) RevokeToken() { // login authenticates to Vault using IAM auth, and sets the client's token. func (c *Client) login(ctx context.Context) error { - authConfig := config.AuthConfigFromEnv() + authConfig := c.authConfig roleToAssumeArn := authConfig.AssumedRoleArn - stsSvc := c.stsSvc + stsSvc := sts.NewFromConfig(c.awsCfg) /* If passing in a role (through VAULT_ASSUMED_ROLE_ARN enviornment variable) to be assumed for Vault authentication, use it instead of the function execution role */ @@ -126,76 +126,138 @@ func (c *Client) login(ctx context.Context) error { c.logger.Debug(fmt.Sprintf("Trying to assume role with arn of %s to authenticate with Vault", roleToAssumeArn)) sessionName := "vault_auth" - result, err := c.stsSvc.AssumeRole(&sts.AssumeRoleInput{ - RoleArn: &roleToAssumeArn, - RoleSessionName: &sessionName, + assumeRoleOutput, err := stsSvc.AssumeRole(ctx, &sts.AssumeRoleInput{ + RoleArn: aws.String(roleToAssumeArn), + RoleSessionName: aws.String(sessionName), }) if err != nil { - return fmt.Errorf("failed to assume role with arn of %s %w", roleToAssumeArn, err) + return fmt.Errorf("failed to assume role with arn of %s: %w", roleToAssumeArn, err) + } + if assumeRoleOutput.Credentials == nil { + return fmt.Errorf("failed to assume role with arn of %s: no credentials returned", roleToAssumeArn) } - c.logger.Debug(fmt.Sprintf("Assumed role successfully with token expiration time: %s ", result.Credentials.Expiration.String())) + c.logger.Debug(fmt.Sprintf("Assumed role successfully with token expiration time: %s ", aws.ToTime(assumeRoleOutput.Credentials.Expiration).String())) - var ses *session.Session + assumedRoleCfg := c.awsCfg.Copy() if authConfig.STSEndpointRegion != "" { - ses = session.Must(session.NewSession(&aws.Config{ - Region: aws.String(authConfig.STSEndpointRegion), - STSRegionalEndpoint: endpoints.RegionalSTSEndpoint, - Credentials: credentials.NewStaticCredentials(*result.Credentials.AccessKeyId, *result.Credentials.SecretAccessKey, *result.Credentials.SessionToken), - })) - } else { - ses = session.Must(session.NewSession(&aws.Config{ - Credentials: credentials.NewStaticCredentials(*result.Credentials.AccessKeyId, *result.Credentials.SecretAccessKey, *result.Credentials.SessionToken), - })) + assumedRoleCfg.Region = authConfig.STSEndpointRegion } + assumedRoleCfg.Credentials = aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider( + aws.ToString(assumeRoleOutput.Credentials.AccessKeyId), + aws.ToString(assumeRoleOutput.Credentials.SecretAccessKey), + aws.ToString(assumeRoleOutput.Credentials.SessionToken), + )) - stsSvc = sts.New(ses) + stsSvc = sts.NewFromConfig(assumedRoleCfg) } - // ignore out - req, _ := stsSvc.GetCallerIdentityRequest(&sts.GetCallerIdentityInput{}) - req.SetContext(ctx) + stsOptions := stsSvc.Options() + if stsOptions.Credentials == nil { + return fmt.Errorf("failed to authenticate with Vault IAM auth provider %q: missing STS credentials provider", authConfig.Provider) + } - if c.authConfig.IAMServerID != "" { - req.HTTPRequest.Header.Add("X-Vault-AWS-IAM-Server-ID", c.authConfig.IAMServerID) + d, err := buildIAMAuthPayload(ctx, stsSvc, authConfig) + if err != nil { + return fmt.Errorf("failed to build the IAM auth payload for provider %q, please try again: %w", authConfig.Provider, err) } - if signErr := req.Sign(); signErr != nil { - return signErr + secret, err := c.VaultClient.Logical().Write(fmt.Sprintf("auth/%s/login", authConfig.Provider), d) + if err != nil { + return fmt.Errorf("failed to authenticate with Vault IAM auth provider %q: %w", authConfig.Provider, err) + } + if secret == nil { + return fmt.Errorf("got no response from the %s authentication provider", authConfig.Provider) } - headers, err := json.Marshal(req.HTTPRequest.Header) + token, err := secret.TokenID() if err != nil { - return err + return fmt.Errorf("error reading token: %w", err) } + c.VaultClient.SetToken(token) - body, err := io.ReadAll(req.HTTPRequest.Body) + return c.updateTokenMetadata(secret) +} + +// buildIAMAuthPayload builds and signs a GetCallerIdentity request, then packages +// it into the payload expected by Vault's AWS IAM auth login endpoint. +func buildIAMAuthPayload(ctx context.Context, stsSvc *sts.Client, authConfig config.AuthConfig) (map[string]interface{}, error) { + stsOptions := stsSvc.Options() + stsRegion := stsOptions.Region + if stsRegion == "" { + stsRegion = defaultSTSRegion + } + + stsEndpoint, err := resolveSTSEndpointURL(ctx, stsOptions) if err != nil { - return err + return nil, fmt.Errorf("failed to resolve STS endpoint URL: %w", err) } - d := make(map[string]interface{}) - d["iam_http_request_method"] = req.HTTPRequest.Method - d["iam_request_url"] = base64.StdEncoding.EncodeToString([]byte(req.HTTPRequest.URL.String())) - d["iam_request_headers"] = base64.StdEncoding.EncodeToString(headers) - d["iam_request_body"] = base64.StdEncoding.EncodeToString(body) - d["role"] = c.authConfig.Role + body := "Action=GetCallerIdentity&Version=2011-06-15" + bodyHash := fmt.Sprintf("%x", sha256.Sum256([]byte(body))) - secret, err := c.VaultClient.Logical().Write(fmt.Sprintf("auth/%s/login", c.authConfig.Provider), d) + httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, stsEndpoint, strings.NewReader(body)) if err != nil { - return err + return nil, fmt.Errorf("failed to build STS GetCallerIdentity request: %w", err) } - if secret == nil { - return fmt.Errorf("got no response from the %s authentication provider", c.authConfig.Provider) + httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") + if authConfig.IAMServerID != "" { + httpReq.Header.Set("X-Vault-AWS-IAM-Server-ID", authConfig.IAMServerID) } - token, err := secret.TokenID() + creds, err := stsOptions.Credentials.Retrieve(ctx) if err != nil { - return fmt.Errorf("error reading token: %s", err) + return nil, fmt.Errorf("failed to retrieve AWS credentials for STS request signing: %w", err) + } + if err := v4.NewSigner().SignHTTP(ctx, creds, httpReq, bodyHash, "sts", stsRegion, time.Now()); err != nil { + return nil, fmt.Errorf("failed to sign STS GetCallerIdentity request: %w", err) } - c.VaultClient.SetToken(token) - return c.updateTokenMetadata(secret) + headers, err := json.Marshal(httpReq.Header) + if err != nil { + return nil, fmt.Errorf("failed to marshal signed STS request headers: %w", err) + } + + return map[string]interface{}{ + "iam_http_request_method": http.MethodPost, + "iam_request_url": base64.StdEncoding.EncodeToString([]byte(stsEndpoint)), + "iam_request_headers": base64.StdEncoding.EncodeToString(headers), + "iam_request_body": base64.StdEncoding.EncodeToString([]byte(body)), + "role": authConfig.Role, + }, nil +} + +// resolveSTSEndpointURL resolves the concrete STS endpoint using the SDK's +// endpoint resolver, then normalizes it to a URL safe for signing. +func resolveSTSEndpointURL(ctx context.Context, opts sts.Options) (string, error) { + resolver := opts.EndpointResolverV2 + if resolver == nil { + resolver = sts.NewDefaultEndpointResolverV2() + } + + region := opts.Region + if region == "" { + region = defaultSTSRegion + } + + endpoint, err := resolver.ResolveEndpoint(ctx, sts.EndpointParameters{ + Region: aws.String(region), + UseDualStack: aws.Bool(opts.EndpointOptions.UseDualStackEndpoint == aws.DualStackEndpointStateEnabled), + UseFIPS: aws.Bool(opts.EndpointOptions.UseFIPSEndpoint == aws.FIPSEndpointStateEnabled), + Endpoint: opts.BaseEndpoint, + }) + if err != nil { + return "", fmt.Errorf("failed to resolve STS endpoint for region %q: %w", region, err) + } + + u := endpoint.URI + u.RawQuery = "" + u.Fragment = "" + if u.Path == "" { + u.Path = "/" + } + + return u.String(), nil } func (c *Client) renew() error { diff --git a/internal/vault/client_test.go b/internal/vault/client_test.go index f26b8cd..cac78c0 100644 --- a/internal/vault/client_test.go +++ b/internal/vault/client_test.go @@ -4,17 +4,25 @@ package vault import ( + "bytes" "context" + "encoding/base64" "encoding/json" "errors" + "io" "net/http" "net/http/httptest" + "net/url" "os" + "strings" "testing" "time" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/sts" + "github.com/aws/aws-sdk-go-v2/aws" + awsconfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/sts" + smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault-lambda-extension/internal/config" "github.com/hashicorp/vault-lambda-extension/internal/ststest" @@ -23,8 +31,9 @@ import ( ) var ( - vaultRequests []*http.Request - secretFunc func() (*api.Secret, error) + vaultRequests []*http.Request + vaultRequestBodies [][]byte + secretFunc func() (*api.Secret, error) with1hLease = &api.Secret{ Auth: &api.SecretAuth{ @@ -42,11 +51,27 @@ var ( } ) +type recordingSTSEndpointResolver struct { + regionSeen string +} + +func (r *recordingSTSEndpointResolver) ResolveEndpoint(_ context.Context, params sts.EndpointParameters) (smithyendpoints.Endpoint, error) { + r.regionSeen = aws.ToString(params.Region) + + u, err := url.Parse("https://sts.us-east-1.amazonaws.com") + if err != nil { + return smithyendpoints.Endpoint{}, err + } + + return smithyendpoints.Endpoint{URI: *u}, nil +} + func TestTokenRenewal(t *testing.T) { vault := fakeVault() defer vault.Close() - ses := session.Must(session.NewSession()) - stsServer := ststest.FakeSTS(ses) + awsCfg, err := awsconfig.LoadDefaultConfig(context.TODO()) + require.NoError(t, err) + stsServer, awsCfg := ststest.FakeSTS(&awsCfg) defer stsServer.Close() generateVaultClient := func() *api.Client { @@ -56,8 +81,6 @@ func TestTokenRenewal(t *testing.T) { require.NoError(t, err) return vaultClient } - stsSvc := sts.New(ses) - t.Run("TestExpired", func(t *testing.T) { now := time.Now() for _, tc := range []struct { @@ -156,7 +179,7 @@ func TestTokenRenewal(t *testing.T) { c := Client{ VaultClient: generateVaultClient(), logger: hclog.Default(), - stsSvc: stsSvc, + awsCfg: awsCfg, authConfig: config.AuthConfig{ Provider: "aws", }, @@ -179,7 +202,7 @@ func TestTokenRenewal(t *testing.T) { c := Client{ VaultClient: generateVaultClient(), logger: hclog.Default(), - stsSvc: stsSvc, + awsCfg: awsCfg, authConfig: config.AuthConfig{ Provider: "aws", }, @@ -205,7 +228,7 @@ func TestTokenRenewal(t *testing.T) { c := Client{ VaultClient: generateVaultClient(), logger: hclog.Default(), - stsSvc: stsSvc, + awsCfg: awsCfg, authConfig: config.AuthConfig{ Provider: "aws", }, @@ -226,7 +249,6 @@ func TestTokenRenewal(t *testing.T) { c := Client{ VaultClient: vaultClient, logger: hclog.Default(), - stsSvc: stsSvc, tokenRenewable: true, tokenExpiry: time.Now().Add(time.Hour), @@ -257,7 +279,6 @@ func TestTokenRenewal(t *testing.T) { c := Client{ VaultClient: vaultClient, logger: hclog.Default(), - stsSvc: stsSvc, tokenRenewable: true, tokenExpiry: time.Now().Add(time.Hour), @@ -283,7 +304,6 @@ func TestTokenRenewal(t *testing.T) { c := Client{ VaultClient: vaultClient, logger: hclog.Default(), - stsSvc: stsSvc, tokenRenewable: false, tokenExpiry: time.Now().Add(time.Hour), @@ -361,12 +381,168 @@ func TestUserAgentHeaderAddition(t *testing.T) { }) } +func TestBuildIAMAuthPayload_SignedHeaders(t *testing.T) { + stsSvc := sts.NewFromConfig(aws.Config{ + Region: "us-east-1", + BaseEndpoint: aws.String("https://sts.us-east-1.amazonaws.com"), + Credentials: aws.NewCredentialsCache( + credentials.NewStaticCredentialsProvider("AKIDEXAMPLE", "secret", "session-token"), + ), + }) + + payload, err := buildIAMAuthPayload(context.Background(), stsSvc, config.AuthConfig{Role: "example-role"}) + require.NoError(t, err) + + headers := decodeIAMRequestHeaders(t, payload) + authorization := headers.Get("Authorization") + require.Contains(t, authorization, "AWS4-HMAC-SHA256") + require.Contains(t, authorization, "Credential=AKIDEXAMPLE/") + require.NotEmpty(t, headers.Get("X-Amz-Date")) + require.Equal(t, "session-token", headers.Get("X-Amz-Security-Token")) +} + +func TestBuildIAMAuthPayload_IncludesVaultIAMServerIDHeader(t *testing.T) { + stsSvc := sts.NewFromConfig(aws.Config{ + Region: "us-east-1", + BaseEndpoint: aws.String("https://sts.us-east-1.amazonaws.com"), + Credentials: aws.NewCredentialsCache( + credentials.NewStaticCredentialsProvider("AKIDEXAMPLE", "secret", "session-token"), + ), + }) + + payload, err := buildIAMAuthPayload(context.Background(), stsSvc, config.AuthConfig{ + IAMServerID: "vault.example.com", + }) + require.NoError(t, err) + + headers := decodeIAMRequestHeaders(t, payload) + require.Equal(t, "vault.example.com", headers.Get("X-Vault-AWS-IAM-Server-ID")) +} + +func TestResolveSTSEndpointURL_DefaultsRegionToUSEast1(t *testing.T) { + resolver := &recordingSTSEndpointResolver{} + + endpoint, err := resolveSTSEndpointURL(context.Background(), sts.Options{ + EndpointResolverV2: resolver, + }) + require.NoError(t, err) + require.Equal(t, defaultSTSRegion, resolver.regionSeen) + require.Equal(t, "https://sts.us-east-1.amazonaws.com/", endpoint) +} + +func TestLogin_MissingCredentialsProviderReturnsMeaningfulError(t *testing.T) { + c := Client{ + logger: hclog.Default(), + awsCfg: aws.Config{}, + authConfig: config.AuthConfig{Provider: "aws"}, + } + + err := c.login(context.Background()) + require.Error(t, err) + require.Contains(t, err.Error(), `failed to authenticate with Vault IAM auth provider "aws": missing STS credentials provider`) +} + +func TestToken_UsesAssumedRoleArnWithSTSEndpointRegion(t *testing.T) { + vault := fakeVault() + defer vault.Close() + + stsServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + require.NoError(t, err) + + if strings.Contains(string(body), "Action=AssumeRole") { + w.Header().Set("Content-Type", "text/xml") + _, writeErr := w.Write([]byte(` + + + ASIAEXAMPLE + assumed-role-secret + assumed-role-session-token + 2030-01-01T00:00:00Z + + + AROAEXAMPLE:vault_auth + arn:aws:sts::123456789012:assumed-role/test-role/vault_auth + + + + example-request-id + +`)) + require.NoError(t, writeErr) + return + } + + http.Error(w, "unexpected STS action", http.StatusBadRequest) + })) + defer stsServer.Close() + + vaultRequests = []*http.Request{} + vaultRequestBodies = [][]byte{} + secretFunc = generateSecretFunc(t, []*api.Secret{with1hLease}) + + vaultClient, err := api.NewClient(&api.Config{Address: vault.URL}) + require.NoError(t, err) + + c := Client{ + VaultClient: vaultClient, + logger: hclog.Default(), + awsCfg: aws.Config{ + Region: "us-east-1", + BaseEndpoint: aws.String(stsServer.URL), + Credentials: aws.NewCredentialsCache( + credentials.NewStaticCredentialsProvider("foo", "foo", "foo"), + ), + }, + authConfig: config.AuthConfig{ + Provider: "aws", + AssumedRoleArn: "arn:aws:iam::123456789012:role/test-role", + STSEndpointRegion: "eu-west-1", + }, + } + + token, err := c.Token(context.Background()) + require.NoError(t, err) + require.Equal(t, "foo-1h-token", token) + require.Equal(t, 1, len(vaultRequests)) + require.Equal(t, "/v1/auth/aws/login", vaultRequests[0].URL.Path) + + payload := decodeVaultRequestPayload(t, vaultRequestBodies[0]) + headers := decodeIAMRequestHeaders(t, payload) + require.Contains(t, headers.Get("Authorization"), "/eu-west-1/sts/") +} + +func decodeIAMRequestHeaders(t *testing.T, payload map[string]interface{}) http.Header { + t.Helper() + + encodedHeaders, ok := payload["iam_request_headers"].(string) + require.True(t, ok) + + headersBytes, err := base64.StdEncoding.DecodeString(encodedHeaders) + require.NoError(t, err) + + var headers http.Header + require.NoError(t, json.Unmarshal(headersBytes, &headers)) + + // Header values include scheme and credential information generated by SigV4. + if strings.TrimSpace(headers.Get("Authorization")) == "" { + t.Fatalf("authorization header is missing in signed iam_request_headers") + } + + return headers +} + func fakeUserAgent(_ *api.Request) string { return userAgent } func fakeVault() *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + if err == nil { + vaultRequestBodies = append(vaultRequestBodies, body) + } + defer func() { vaultRequests = append(vaultRequests, r) }() @@ -388,6 +564,15 @@ func fakeVault() *httptest.Server { })) } +func decodeVaultRequestPayload(t *testing.T, body []byte) map[string]interface{} { + t.Helper() + + var payload map[string]interface{} + require.NoError(t, json.Unmarshal(bytes.TrimSpace(body), &payload)) + + return payload +} + func generateSecretFunc(t *testing.T, secrets []*api.Secret) func() (*api.Secret, error) { t.Helper() return func() (*api.Secret, error) { diff --git a/main.go b/main.go index c895971..09c4e09 100644 --- a/main.go +++ b/main.go @@ -17,9 +17,7 @@ import ( "syscall" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/session" + awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/api" @@ -126,16 +124,17 @@ func (h *handler) runExtension(ctx context.Context, wg *sync.WaitGroup) (func(co return nil, errors.New("missing VLE_VAULT_ADDR, VAULT_ADDR, VAULT_AUTH_PROVIDER or VAULT_AUTH_ROLE environment variables") } - var ses *session.Session + awsLoadOptions := []func(*awsconfig.LoadOptions) error{} if authConfig.STSEndpointRegion != "" { - ses = session.Must(session.NewSession(&aws.Config{ - Region: aws.String(authConfig.STSEndpointRegion), - STSRegionalEndpoint: endpoints.RegionalSTSEndpoint, - })) - } else { - ses = session.Must(session.NewSession()) + awsLoadOptions = append(awsLoadOptions, awsconfig.WithRegion(authConfig.STSEndpointRegion)) } - client, err := vault.NewClient(config.ExtensionName, config.ExtensionVersion, h.logger.Named("vault-client"), vaultConfig, authConfig, ses) + + awsCfg, err := awsconfig.LoadDefaultConfig(ctx, awsLoadOptions...) + if err != nil { + return nil, fmt.Errorf("error loading AWS SDK config: %w", err) + } + + client, err := vault.NewClient(config.ExtensionName, config.ExtensionVersion, h.logger.Named("vault-client"), vaultConfig, authConfig, awsCfg) if err != nil { return nil, fmt.Errorf("error getting client: %w", err) } else if client == nil { diff --git a/quick-start/terraform/aws.tf b/quick-start/terraform/aws.tf index 7c0c1ff..a5423d3 100644 --- a/quick-start/terraform/aws.tf +++ b/quick-start/terraform/aws.tf @@ -25,6 +25,11 @@ data "aws_ami" "ubuntu" { values = ["hvm"] } + filter { + name = "architecture" + values = ["x86_64"] + } + owners = ["888995627335"] # Canonical } diff --git a/quick-start/terraform/variables.tf b/quick-start/terraform/variables.tf index af0c1a2..2cbe43a 100644 --- a/quick-start/terraform/variables.tf +++ b/quick-start/terraform/variables.tf @@ -18,7 +18,7 @@ variable "vault_zip_file" { # Instance size variable "instance_type" { - default = "t2.micro" + default = "t3.micro" } # DB instance size diff --git a/test/api/Dockerfile b/test/api/Dockerfile index 950abf5..f6612b6 100644 --- a/test/api/Dockerfile +++ b/test/api/Dockerfile @@ -1,7 +1,7 @@ # Copyright IBM Corp. 2020, 2025 # SPDX-License-Identifier: MPL-2.0 -FROM docker.mirror.hashicorp.services/golang:1.15-alpine3.13 as builder +FROM docker.mirror.hashicorp.services/golang:1.25.7-alpine AS builder COPY . /go/src/ WORKDIR /go/src/ diff --git a/test/docker-compose.yaml b/test/docker-compose.yaml index 0ead88b..1dffba2 100644 --- a/test/docker-compose.yaml +++ b/test/docker-compose.yaml @@ -29,9 +29,12 @@ services: - AWS_SECRET_ACCESS_KEY - AWS_SESSION_TOKEN - VAULT_LOG_LEVEL + vault: - image: docker.mirror.hashicorp.services/vault:1.6.2 + image: hashicorp/vault:1.21.1 command: vault server -dev -log-level=err environment: - VAULT_DEV_ROOT_TOKEN_ID=root - - VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \ No newline at end of file + - VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 + cap_add: + - IPC_LOCK \ No newline at end of file diff --git a/test/lambda/Dockerfile b/test/lambda/Dockerfile index 6430450..4593d5e 100644 --- a/test/lambda/Dockerfile +++ b/test/lambda/Dockerfile @@ -1,9 +1,9 @@ # Copyright IBM Corp. 2020, 2025 # SPDX-License-Identifier: MPL-2.0 -FROM docker.mirror.hashicorp.services/vault:1.6.2 as vault +FROM docker.io/hashicorp/vault:1.21.1 AS vault -FROM docker.mirror.hashicorp.services/golang:1.15-alpine3.13 as builder +FROM docker.mirror.hashicorp.services/golang:1.25.7-alpine AS builder COPY . /go/src/ WORKDIR /go/src/