1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-03-27 21:49:15 +02:00

refactor(vault): Refactor vault package (#5148)

* move to old package

* go mod

* remove old

* refactor done

* Update pkg/vault/oidc.go

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>

* commit suggestions

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>

* commit suggestions

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>

* commit suggestions

---------

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
This commit is contained in:
Googlom 2024-10-22 13:29:34 +05:00 committed by GitHub
parent 4eb1756b54
commit 5c47be3f8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 556 additions and 493 deletions

View File

@ -41,20 +41,22 @@ func (v vaultRotateSecretIDUtilsBundle) UpdateSecretInStore(config *vaultRotateS
func vaultRotateSecretId(config vaultRotateSecretIdOptions, telemetryData *telemetry.CustomData) {
vaultConfig := &vault.Config{
vaultConfig := &vault.ClientConfig{
Config: &api.Config{
Address: config.VaultServerURL,
},
Namespace: config.VaultNamespace,
RoleID: GeneralConfig.VaultRoleID,
SecretID: GeneralConfig.VaultRoleSecretID,
}
client, err := vault.NewClientWithAppRole(vaultConfig, GeneralConfig.VaultRoleID, GeneralConfig.VaultRoleSecretID)
client, err := vault.NewClient(vaultConfig)
if err != nil {
log.Entry().WithError(err).Fatal("could not create Vault client")
}
defer client.MustRevokeToken()
utils := vaultRotateSecretIDUtilsBundle{
Client: &client,
Client: client,
config: &config,
updateFunc: writeVaultSecretIDToStore,
}

13
go.mod
View File

@ -32,8 +32,9 @@ require (
github.com/google/go-containerregistry v0.19.0
github.com/google/go-github/v45 v45.2.0
github.com/google/uuid v1.6.0
github.com/hashicorp/go-retryablehttp v0.7.2
github.com/hashicorp/vault/api v1.9.2
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/hashicorp/vault/api v1.15.0
github.com/hashicorp/vault/api/auth/approle v0.8.0
github.com/iancoleman/orderedmap v0.2.0
github.com/imdario/mergo v0.3.15
github.com/influxdata/influxdb-client-go/v2 v2.13.0
@ -76,7 +77,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
@ -87,7 +88,7 @@ require (
github.com/distribution/reference v0.6.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
@ -152,7 +153,6 @@ require (
github.com/aws/smithy-go v1.20.4 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/buildpacks/imgutil v0.0.0-20230919143643-4ec9360d5f02 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/containerd v1.7.20 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
@ -164,7 +164,7 @@ require (
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logr/logr v1.4.1 // indirect
@ -190,7 +190,6 @@ require (
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect

46
go.sum
View File

@ -196,10 +196,8 @@ github.com/buildpacks/imgutil v0.0.0-20230919143643-4ec9360d5f02/go.mod h1:Ade+4
github.com/buildpacks/lifecycle v0.18.5 h1:lfoUX8jYCUZ2/Tr2AopaRjinqDivkNkcTChzysQTo00=
github.com/buildpacks/lifecycle v0.18.5/go.mod h1:Kvuu9IWABPLXc6yHCMtbdmgrGEi7QEiVzi5GGtcAkW0=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -287,9 +285,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
@ -321,8 +318,8 @@ github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lK
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
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=
@ -565,14 +562,13 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
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 v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
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-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
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/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs=
@ -591,8 +587,10 @@ github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvH
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as=
github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8=
github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/pj5DA=
github.com/hashicorp/vault/api v1.15.0/go.mod h1:+5YTO09JGn0u+b6ySD/LLVf8WkJCPLAL2Vkmrn2+CM8=
github.com/hashicorp/vault/api/auth/approle v0.8.0 h1:FuVtWZ0xD6+wz1x0l5s0b4852RmVXQNEiKhVXt6lfQY=
github.com/hashicorp/vault/api/auth/approle v0.8.0/go.mod h1:NV7O9r5JUtNdVnqVZeMHva81AIdpG0WoIQohNt1VCPM=
github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0=
github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@ -678,15 +676,11 @@ github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kN
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
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-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
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=
@ -889,7 +883,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
@ -1015,7 +1008,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1102,7 +1094,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1158,7 +1149,6 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/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-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1181,10 +1171,7 @@ golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210616094352-59db8d763f22/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-20211216021012-1d35b9e2eb4e/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1196,7 +1183,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@ -1206,8 +1192,6 @@ golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1222,8 +1206,6 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@ -47,7 +47,7 @@ func TestVaultIntegrationGetSecret(t *testing.T) {
assert.NoError(t, err)
port, err := vaultContainer.MappedPort(ctx, "8200")
host := fmt.Sprintf("http://%s:%s", ip, port.Port())
config := &vault.Config{Config: &api.Config{Address: host}}
config := &vault.ClientConfig{Config: &api.Config{Address: host}}
// setup vault for testing
secretData := SecretData{
"key1": "value1",
@ -55,7 +55,7 @@ func TestVaultIntegrationGetSecret(t *testing.T) {
}
setupVault(t, config, testToken, secretData)
client, err := vault.NewClient(config, testToken)
client, err := vault.NewClientWithToken(config, testToken)
assert.NoError(t, err)
secret, err := client.GetKvSecret("secret/test")
assert.NoError(t, err)
@ -93,14 +93,14 @@ func TestVaultIntegrationWriteSecret(t *testing.T) {
assert.NoError(t, err)
port, err := vaultContainer.MappedPort(ctx, "8200")
host := fmt.Sprintf("http://%s:%s", ip, port.Port())
config := &vault.Config{Config: &api.Config{Address: host}}
config := &vault.ClientConfig{Config: &api.Config{Address: host}}
// setup vault for testing
secretData := map[string]string{
"key1": "value1",
"key2": "value2",
}
client, err := vault.NewClient(config, testToken)
client, err := vault.NewClientWithToken(config, testToken)
assert.NoError(t, err)
err = client.WriteKvSecret("secret/test", secretData)
@ -159,16 +159,17 @@ func TestVaultIntegrationAppRole(t *testing.T) {
assert.NoError(t, err)
port, err := vaultContainer.MappedPort(ctx, "8200")
host := fmt.Sprintf("http://%s:%s", ip, port.Port())
config := &vault.Config{Config: &api.Config{Address: host}}
config := &vault.ClientConfig{Config: &api.Config{Address: host}}
secretIDMetadata := map[string]interface{}{
"field1": "value1",
}
roleID, secretID := setupVaultAppRole(t, config, testToken, appRolePath, secretIDMetadata)
config.RoleID = roleID
config.SecretID = secretID
t.Run("Test Vault AppRole login", func(t *testing.T) {
client, err := vault.NewClientWithAppRole(config, roleID, secretID)
client, err := vault.NewClient(config)
assert.NoError(t, err)
secret, err := client.GetSecret("auth/token/lookup-self")
meta := secret.Data["meta"].(SecretData)
@ -178,7 +179,7 @@ func TestVaultIntegrationAppRole(t *testing.T) {
})
t.Run("Test Vault AppRoleTTL Fetch", func(t *testing.T) {
client, err := vault.NewClient(config, testToken)
client, err := vault.NewClientWithToken(config, testToken)
assert.NoError(t, err)
ttl, err := client.GetAppRoleSecretIDTtl(secretID, appRoleName)
assert.NoError(t, err)
@ -186,7 +187,7 @@ func TestVaultIntegrationAppRole(t *testing.T) {
})
t.Run("Test Vault AppRole Rotation", func(t *testing.T) {
client, err := vault.NewClient(config, testToken)
client, err := vault.NewClientWithToken(config, testToken)
assert.NoError(t, err)
newSecretID, err := client.GenerateNewAppRoleSecret(secretID, appRoleName)
assert.NoError(t, err)
@ -194,7 +195,7 @@ func TestVaultIntegrationAppRole(t *testing.T) {
assert.NotEqual(t, secretID, newSecretID)
// verify metadata is not broken
client, err = vault.NewClientWithAppRole(config, roleID, newSecretID)
client, err = vault.NewClient(config)
assert.NoError(t, err)
secret, err := client.GetSecret("auth/token/lookup-self")
meta := secret.Data["meta"].(SecretData)
@ -204,7 +205,7 @@ func TestVaultIntegrationAppRole(t *testing.T) {
})
t.Run("Test Fetching RoleName from vault", func(t *testing.T) {
client, err := vault.NewClientWithAppRole(config, roleID, secretID)
client, err := vault.NewClient(config)
assert.NoError(t, err)
fetchedRoleName, err := client.GetAppRoleName()
assert.NoError(t, err)
@ -238,16 +239,18 @@ func TestVaultIntegrationTokenRevocation(t *testing.T) {
assert.NoError(t, err)
port, err := vaultContainer.MappedPort(ctx, "8200")
host := fmt.Sprintf("http://%s:%s", ip, port.Port())
config := &vault.Config{Config: &api.Config{Address: host}}
config := &vault.ClientConfig{Config: &api.Config{Address: host}}
secretIDMetadata := map[string]interface{}{
"field1": "value1",
}
roleID, secretID := setupVaultAppRole(t, config, testToken, appRolePath, secretIDMetadata)
config.RoleID = roleID
config.SecretID = secretID
t.Run("Test Revocation works", func(t *testing.T) {
client, err := vault.NewClientWithAppRole(config, roleID, secretID)
client, err := vault.NewClient(config)
assert.NoError(t, err)
secret, err := client.GetSecret("auth/token/lookup-self")
meta := secret.Data["meta"].(SecretData)
@ -263,7 +266,7 @@ func TestVaultIntegrationTokenRevocation(t *testing.T) {
})
}
func setupVaultAppRole(t *testing.T, config *vault.Config, token, appRolePath string, metadata map[string]interface{}) (string, string) {
func setupVaultAppRole(t *testing.T, config *vault.ClientConfig, token, appRolePath string, metadata map[string]interface{}) (string, string) {
t.Helper()
client, err := api.NewClient(config.Config)
assert.NoError(t, err)
@ -302,7 +305,7 @@ func setupVaultAppRole(t *testing.T, config *vault.Config, token, appRolePath st
return roleID.(string), secretID.(string)
}
func setupVault(t *testing.T, config *vault.Config, token string, secret SecretData) {
func setupVault(t *testing.T, config *vault.ClientConfig, token string, secret SecretData) {
t.Helper()
client, err := api.NewClient(config.Config)
assert.NoError(t, err)

View File

@ -87,6 +87,7 @@ var globalVaultClient *vault.Client
func GlobalVaultClient() VaultClient {
// an interface containing a nil pointer is considered non-nil in Go
// It is nil if Vault is not configured
if globalVaultClient == nil {
return nil
}
@ -122,15 +123,17 @@ func GetVaultClientFromConfig(config map[string]interface{}, creds VaultCredenti
namespace = config["vaultNamespace"].(string)
log.Entry().Debugf(" with namespace %s", namespace)
}
var client vault.Client
var client *vault.Client
var err error
clientConfig := &vault.Config{Config: &api.Config{Address: address}, Namespace: namespace}
clientConfig := &vault.ClientConfig{Config: &api.Config{Address: address}, Namespace: namespace}
if creds.VaultToken != "" {
log.Entry().Debugf(" with Token authentication")
client, err = vault.NewClient(clientConfig, creds.VaultToken)
client, err = vault.NewClientWithToken(clientConfig, creds.VaultToken)
} else {
log.Entry().Debugf(" with AppRole authentication")
client, err = vault.NewClientWithAppRole(clientConfig, creds.AppRoleID, creds.AppRoleSecretID)
clientConfig.RoleID = creds.AppRoleID
clientConfig.SecretID = creds.AppRoleSecretID
client, err = vault.NewClient(clientConfig)
}
if err != nil {
log.Entry().Info(" failed")
@ -138,7 +141,7 @@ func GetVaultClientFromConfig(config map[string]interface{}, creds VaultCredenti
}
// Set global vault client for usage in steps
globalVaultClient = &client
globalVaultClient = client
log.Entry().Info(" succeeded")
return client, nil

View File

@ -2,77 +2,173 @@ package vault
import (
"context"
"encoding/json"
"fmt"
"github.com/SAP/jenkins-library/pkg/log"
vaultAPI "github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/api/auth/approle"
"github.com/pkg/errors"
"io"
"net/http"
"path"
"strconv"
"strings"
"time"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/hashicorp/vault/api"
)
// Client handles communication with Vault
type Client struct {
lClient logicalClient
config *Config
vaultApiClient *vaultAPI.Client
logical logicalClient
cfg *ClientConfig
}
// Config contains the vault client configuration
type Config struct {
*api.Config
AppRoleMountPoint string
type ClientConfig struct {
*vaultAPI.Config
Namespace string
AppRoleMountPoint string
RoleID string
SecretID string
}
// logicalClient interface for mocking
type logicalClient interface {
Read(string) (*api.Secret, error)
Write(string, map[string]interface{}) (*api.Secret, error)
Read(string) (*vaultAPI.Secret, error)
Write(string, map[string]interface{}) (*vaultAPI.Secret, error)
}
type VaultCredentials struct {
AppRoleID string
AppRoleSecretID string
VaultToken string
}
// NewClient instantiates a Client and sets the specified token
func NewClient(config *Config, token string) (Client, error) {
if config == nil {
config = &Config{Config: api.DefaultConfig()}
func newClient(cfg *ClientConfig) (*Client, error) {
if cfg == nil {
cfg = &ClientConfig{Config: vaultAPI.DefaultConfig()}
}
client, err := api.NewClient(config.Config)
var err error
c := &Client{cfg: cfg}
c.vaultApiClient, err = vaultAPI.NewClient(cfg.Config)
if err != nil {
return Client{}, err
return nil, err
}
if config.Namespace != "" {
client.SetNamespace(config.Namespace)
c.logical = c.vaultApiClient.Logical()
if cfg.Namespace != "" {
c.vaultApiClient.SetNamespace(cfg.Namespace)
}
client.SetToken(token)
return Client{client.Logical(), config}, nil
return c, nil
}
// NewClientWithAppRole instantiates a new client and obtains a token via the AppRole auth method
func NewClientWithAppRole(config *Config, roleID, secretID string) (Client, error) {
if config == nil {
config = &Config{Config: api.DefaultConfig()}
}
if config.AppRoleMountPoint == "" {
config.AppRoleMountPoint = "auth/approle"
}
client, err := api.NewClient(config.Config)
func NewClient(cfg *ClientConfig) (*Client, error) {
c, err := newClient(cfg)
if err != nil {
return Client{}, err
return nil, errors.Wrap(err, "vault client initialization failed")
}
applyApiClientRetryConfiguration(c.vaultApiClient)
initialLoginDone := make(chan struct{})
go c.startTokenLifecycleManager(initialLoginDone) // this goroutine ends with main goroutine
// wait for initial login or a failure
<-initialLoginDone
// In case of a failure, the function returns an unauthorized client, which will cause subsequent requests to fail.
return c, nil
}
func NewClientWithToken(cfg *ClientConfig, token string) (*Client, error) {
c, err := newClient(cfg)
if err != nil {
return nil, errors.Wrap(err, "vault client initialization failed")
}
client.SetMinRetryWait(time.Second * 5)
client.SetMaxRetryWait(time.Second * 90)
client.SetMaxRetries(3)
client.SetCheckRetry(func(ctx context.Context, resp *http.Response, err error) (bool, error) {
c.vaultApiClient.SetToken(token)
return c, nil
}
func (c *Client) startTokenLifecycleManager(initialLoginDone chan struct{}) {
defer func() {
// make sure to close channel to avoid blocking of the caller
_, open := <-initialLoginDone
if open {
close(initialLoginDone)
}
}()
initialLoginSucceed := false
for i := 0; i < c.vaultApiClient.MaxRetries(); i++ {
vaultLoginResp, err := c.login()
if err != nil {
log.Entry().Errorf("unable to authenticate to Vault: %v", err)
continue
}
if !initialLoginSucceed {
initialLoginDone <- struct{}{}
close(initialLoginDone)
initialLoginSucceed = true
}
tokenErr := c.manageTokenLifecycle(vaultLoginResp)
if tokenErr != nil {
log.Entry().Errorf("unable to start managing token lifecycle: %v", err)
continue
}
}
}
// Starts token lifecycle management. Returns only fatal errors as errors,
// otherwise returns nil, so we can attempt login again.
func (c *Client) manageTokenLifecycle(authResp *vaultAPI.Secret) error {
if !authResp.Auth.Renewable {
log.Entry().Debugf("Token is not configured to be renewable. Re-attempting login.")
return nil
}
watcher, err := c.vaultApiClient.NewLifetimeWatcher(&vaultAPI.LifetimeWatcherInput{Secret: authResp})
if err != nil {
return fmt.Errorf("unable to initialize new lifetime watcher for renewing auth token: %w", err)
}
go watcher.Start()
defer watcher.Stop()
for {
select {
// `DoneCh` will return if renewal fails, or if the remaining lease
// duration is under a built-in threshold and either renewing is not
// extending it or renewing is disabled. In any case, the caller
// needs to attempt to log in again.
case err := <-watcher.DoneCh():
if err != nil {
log.Entry().Printf("Failed to renew Vault token: %v. Re-attempting login.", err)
return nil
}
// This occurs once the token has reached max TTL.
log.Entry().Printf("Token can no longer be renewed. Re-attempting login.")
return nil
// Successfully completed renewal
case <-watcher.RenewCh():
log.Entry().Printf("Vault token successfully renewed")
}
}
}
func (c *Client) login() (*vaultAPI.Secret, error) {
appRoleAuth, err := approle.NewAppRoleAuth(c.cfg.RoleID, &approle.SecretID{FromString: c.cfg.SecretID})
if err != nil {
return nil, fmt.Errorf("unable to initialize appRole auth method: %w", err)
}
authInfo, err := c.vaultApiClient.Auth().Login(context.Background(), appRoleAuth)
if err != nil {
return nil, fmt.Errorf("unable to login to appRole auth method: %w", err)
}
if authInfo == nil {
return nil, fmt.Errorf("no auth info was returned after login")
}
return authInfo, nil
}
func applyApiClientRetryConfiguration(vaultApiClient *vaultAPI.Client) {
vaultApiClient.SetMinRetryWait(time.Second * 5)
vaultApiClient.SetMaxRetryWait(time.Second * 90)
vaultApiClient.SetMaxRetries(3)
vaultApiClient.SetCheckRetry(func(ctx context.Context, resp *http.Response, err error) (bool, error) {
if resp != nil {
log.Entry().Debugln("Vault response: ", resp.Status, resp.StatusCode, err)
} else {
@ -89,7 +185,7 @@ func NewClientWithAppRole(config *Config, roleID, secretID string) (Client, erro
log.Entry().Infoln("err = io.EOF is true")
}
retry, err := api.DefaultRetryPolicy(ctx, resp, err)
retry, err := vaultAPI.DefaultRetryPolicy(ctx, resp, err)
if err != nil || err == io.EOF || isEOF || retry {
log.Entry().Infoln("Retrying vault request...")
@ -97,328 +193,4 @@ func NewClientWithAppRole(config *Config, roleID, secretID string) (Client, erro
}
return false, nil
})
if config.Namespace != "" {
client.SetNamespace(config.Namespace)
}
result, err := client.Logical().Write(path.Join(config.AppRoleMountPoint, "/login"), map[string]interface{}{
"role_id": roleID,
"secret_id": secretID,
})
if err != nil {
return Client{}, err
}
authInfo := result.Auth
if authInfo == nil || authInfo.ClientToken == "" {
return Client{}, fmt.Errorf("Could not obtain token from approle with role_id %s", roleID)
}
return NewClient(config, authInfo.ClientToken)
}
// GetSecret uses the given path to fetch a secret from vault
func (v Client) GetSecret(path string) (*api.Secret, error) {
path = sanitizePath(path)
c := v.lClient
secret, err := c.Read(path)
if err != nil {
return nil, err
}
return secret, nil
}
// GetKvSecret reads secret from the KV engine.
// It Automatically transforms the logical path to the HTTP API Path for the corresponding KV Engine version
func (v Client) GetKvSecret(path string) (map[string]string, error) {
path = sanitizePath(path)
mountpath, version, err := v.getKvInfo(path)
if err != nil {
return nil, err
}
if version == 2 {
path = addPrefixToKvPath(path, mountpath, "data")
} else if version != 1 {
return nil, fmt.Errorf("KV Engine in version %d is currently not supported", version)
}
secret, err := v.GetSecret(path)
if secret == nil || err != nil {
return nil, err
}
var rawData interface{}
switch version {
case 1:
rawData = secret.Data
case 2:
var ok bool
rawData, ok = secret.Data["data"]
if !ok {
return nil, fmt.Errorf("Missing 'data' field in response: %v", rawData)
}
}
data, ok := rawData.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("Excpected 'data' field to be a map[string]interface{} but got %T instead", rawData)
}
secretData := make(map[string]string, len(data))
for k, v := range data {
switch t := v.(type) {
case string:
secretData[k] = t
case int:
secretData[k] = fmt.Sprintf("%d", t)
default:
jsonBytes, err := json.Marshal(t)
if err != nil {
log.Entry().Warnf("failed to parse Vault secret key %q, error: %s", k, err.Error())
continue
}
secretData[k] = string(jsonBytes)
}
}
return secretData, nil
}
// WriteKvSecret writes secret to kv engine
func (v Client) WriteKvSecret(path string, newSecret map[string]string) error {
oldSecret, err := v.GetKvSecret(path)
if err != nil {
return err
}
secret := make(map[string]interface{}, len(oldSecret))
for k, v := range oldSecret {
secret[k] = v
}
for k, v := range newSecret {
secret[k] = v
}
path = sanitizePath(path)
mountpath, version, err := v.getKvInfo(path)
if err != nil {
return err
}
if version == 2 {
path = addPrefixToKvPath(path, mountpath, "data")
secret = map[string]interface{}{"data": secret}
} else if version != 1 {
return fmt.Errorf("KV Engine in version %d is currently not supported", version)
}
_, err = v.lClient.Write(path, secret)
return err
}
// GenerateNewAppRoleSecret creates a new secret-id
func (v *Client) GenerateNewAppRoleSecret(secretID, appRoleName string) (string, error) {
appRolePath := v.getAppRolePath(appRoleName)
secretIDData, err := v.lookupSecretID(secretID, appRolePath)
if err != nil {
return "", err
}
reqPath := sanitizePath(path.Join(appRolePath, "/secret-id"))
// we preserve metadata which was attached to the secret-id
json, err := json.Marshal(secretIDData["metadata"])
if err != nil {
return "", err
}
secret, err := v.lClient.Write(reqPath, map[string]interface{}{
"metadata": string(json),
})
if err != nil {
return "", err
}
if secret == nil || secret.Data == nil {
return "", fmt.Errorf("Could not generate new approle secret-id for approle path %s", reqPath)
}
secretIDRaw, ok := secret.Data["secret_id"]
if !ok {
return "", fmt.Errorf("Vault response for path %s did not contain a new secret-id", reqPath)
}
newSecretID, ok := secretIDRaw.(string)
if !ok {
return "", fmt.Errorf("New secret-id from approle path %s has an unexpected type %T expected 'string'", reqPath, secretIDRaw)
}
return newSecretID, nil
}
// GetAppRoleSecretIDTtl returns the remaining time until the given secret-id expires
func (v *Client) GetAppRoleSecretIDTtl(secretID, roleName string) (time.Duration, error) {
appRolePath := v.getAppRolePath(roleName)
data, err := v.lookupSecretID(secretID, appRolePath)
if err != nil {
return 0, err
}
if data == nil || data["expiration_time"] == nil {
return 0, fmt.Errorf("Could not load secret-id information from path %s", appRolePath)
}
expiration, ok := data["expiration_time"].(string)
if !ok || expiration == "" {
return 0, fmt.Errorf("Could not handle get expiration time for secret-id from path %s", appRolePath)
}
expirationDate, err := time.Parse(time.RFC3339, expiration)
if err != nil {
return 0, err
}
ttl := expirationDate.Sub(time.Now())
if ttl < 0 {
return 0, nil
}
return ttl, nil
}
// RevokeToken revokes the token which is currently used.
// The client can't be used anymore after this function was called.
func (v Client) RevokeToken() error {
_, err := v.lClient.Write("auth/token/revoke-self", map[string]interface{}{})
return err
}
// MustRevokeToken same as RevokeToken but the programm is terminated with an error if this fails.
// Should be used in defer statements only.
func (v Client) MustRevokeToken() {
if err := v.RevokeToken(); err != nil {
log.Entry().WithError(err).Fatal("Could not revoke token")
}
}
// GetAppRoleName returns the AppRole role name which was used to authenticate.
// Returns "" when AppRole authentication wasn't used
func (v *Client) GetAppRoleName() (string, error) {
const lookupPath = "auth/token/lookup-self"
secret, err := v.GetSecret(lookupPath)
if err != nil {
return "", err
}
if secret.Data == nil {
return "", fmt.Errorf("Could not lookup token information: %s", lookupPath)
}
meta, ok := secret.Data["meta"]
if !ok {
return "", fmt.Errorf("Token info did not contain metadata %s", lookupPath)
}
metaMap, ok := meta.(map[string]interface{})
if !ok {
return "", fmt.Errorf("Token info field 'meta' is not a map: %s", lookupPath)
}
roleName := metaMap["role_name"]
if roleName == nil {
return "", nil
}
roleNameStr, ok := roleName.(string)
if !ok {
// when approle authentication is not used vault admins can use the role_name field with other type
// so no error in this case
return "", nil
}
return roleNameStr, nil
}
// SetAppRoleMountPoint sets the path under which the approle auth backend is mounted
func (v *Client) SetAppRoleMountPoint(appRoleMountpoint string) {
v.config.AppRoleMountPoint = appRoleMountpoint
}
func (v *Client) getAppRolePath(roleName string) string {
appRoleMountPoint := v.config.AppRoleMountPoint
if appRoleMountPoint == "" {
appRoleMountPoint = "auth/approle"
}
return path.Join(appRoleMountPoint, "role", roleName)
}
func sanitizePath(path string) string {
path = strings.TrimSpace(path)
path = strings.TrimPrefix(path, "/")
path = strings.TrimSuffix(path, "/")
return path
}
func addPrefixToKvPath(p, mountPath, apiPrefix string) string {
switch {
case p == mountPath, p == strings.TrimSuffix(mountPath, "/"):
return path.Join(mountPath, apiPrefix)
default:
p = strings.TrimPrefix(p, mountPath)
return path.Join(mountPath, apiPrefix, p)
}
}
func (v *Client) getKvInfo(path string) (string, int, error) {
secret, err := v.GetSecret("sys/internal/ui/mounts/" + path)
if err != nil {
return "", 0, err
}
if secret == nil {
return "", 0, fmt.Errorf("Failed to get version and engine mountpoint for path: %s", path)
}
var mountPath string
if mountPathRaw, ok := secret.Data["path"]; ok {
mountPath = mountPathRaw.(string)
}
options := secret.Data["options"]
if options == nil {
return mountPath, 1, nil
}
versionRaw := options.(map[string]interface{})["version"]
if versionRaw == nil {
return mountPath, 1, nil
}
version := versionRaw.(string)
if version == "" {
return mountPath, 1, nil
}
vNumber, err := strconv.Atoi(version)
if err != nil {
return mountPath, 0, err
}
return mountPath, vNumber, nil
}
func (v *Client) lookupSecretID(secretID, appRolePath string) (map[string]interface{}, error) {
reqPath := sanitizePath(path.Join(appRolePath, "/secret-id/lookup"))
secret, err := v.lClient.Write(reqPath, map[string]interface{}{
"secret_id": secretID,
})
if err != nil {
return nil, err
}
return secret.Data, nil
}

23
pkg/vault/helpers.go Normal file
View File

@ -0,0 +1,23 @@
package vault
import (
"path"
"strings"
)
func sanitizePath(path string) string {
path = strings.TrimSpace(path)
path = strings.TrimPrefix(path, "/")
path = strings.TrimSuffix(path, "/")
return path
}
func addPrefixToKvPath(p, mountPath, apiPrefix string) string {
switch {
case p == mountPath, p == strings.TrimSuffix(mountPath, "/"):
return path.Join(mountPath, apiPrefix)
default:
p = strings.TrimPrefix(p, mountPath)
return path.Join(mountPath, apiPrefix, p)
}
}

View File

@ -13,39 +13,47 @@ import (
"github.com/pkg/errors"
)
type JwtPayload struct {
type jwtPayload struct {
Expire int64 `json:"exp"`
}
// getOIDCToken returns the generated OIDC token and sets it in the env
func (v Client) getOIDCToken(roleID string) (string, error) {
func (c *Client) getOIDCToken(roleID string) (string, error) {
oidcPath := sanitizePath(path.Join("identity/oidc/token/", roleID))
c := v.lClient
jwt, err := c.Read(oidcPath)
jwt, err := c.logical.Read(oidcPath)
if err != nil {
return "", err
}
token := jwt.Data["token"].(string)
if token == "" {
return "", fmt.Errorf("received an empty token")
}
log.RegisterSecret(token)
os.Setenv("PIPER_OIDCIdentityToken", token)
return token, nil
}
// getJWTTokenPayload returns the payload of the JWT token using base64 decoding
func getJWTTokenPayload(token string) ([]byte, error) {
// getJWTPayload returns the payload of the JWT token using base64 decoding
func getJWTPayload(token string) (*jwtPayload, error) {
parts := strings.Split(token, ".")
if len(parts) >= 2 {
substr := parts[1]
decodedBytes, err := base64.RawStdEncoding.DecodeString(substr)
if err != nil {
return nil, errors.Wrap(err, "JWT payload couldn't be decoded: %s")
}
return decodedBytes, nil
if len(parts) < 2 {
return nil, fmt.Errorf("not a valid JWT token")
}
return nil, fmt.Errorf("Not a valid JWT token")
decodedBytes, err := base64.RawStdEncoding.DecodeString(parts[1])
if err != nil {
return nil, errors.Wrap(err, "JWT payload couldn't be decoded: %s")
}
var payload jwtPayload
if err = json.Unmarshal(decodedBytes, &payload); err != nil {
return nil, errors.Wrap(err, "JWT unmarshal failed")
}
return &payload, nil
}
func oidcTokenIsValid(token string) bool {
@ -53,34 +61,28 @@ func oidcTokenIsValid(token string) bool {
return false
}
payload, err := getJWTTokenPayload(token)
jwtTokenPayload, err := getJWTPayload(token)
if err != nil {
log.Entry().Debugf("OIDC token couldn't be validated: %s", err)
return false
}
var jwtPayload JwtPayload
err = json.Unmarshal(payload, &jwtPayload)
if err != nil {
log.Entry().Debugf("OIDC token couldn't be validated: %s", err)
return false
}
expiryTime := time.Unix(jwtPayload.Expire, 0)
expiryTime := time.Unix(jwtTokenPayload.Expire, 0)
currentTime := time.Now()
return expiryTime.After(currentTime)
}
// GetOIDCTokenByValidation returns the token if token is expired then get a new token else return old token
func (v Client) GetOIDCTokenByValidation(roleID string) (string, error) {
func (c *Client) GetOIDCTokenByValidation(roleID string) (string, error) {
token := os.Getenv("PIPER_OIDCIdentityToken")
if oidcTokenIsValid(token) {
return token, nil
}
token, err := v.getOIDCToken(roleID)
if token == "" || err != nil {
log.Entry().Debug("obtaining new OIDC token")
token, err := c.getOIDCToken(roleID)
if err != nil {
return "", err
}

View File

@ -28,7 +28,7 @@ func TestOIDC(t *testing.T) {
// init
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", oidcPath).Return(mockJwt, nil)
// run
@ -50,7 +50,7 @@ func TestOIDC(t *testing.T) {
t.Setenv("PIPER_OIDCIdentityToken", token)
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", oidcPath).Return(mockJwt, nil)
// run
@ -72,7 +72,7 @@ func TestOIDC(t *testing.T) {
t.Setenv("PIPER_OIDCIdentityToken", token)
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", oidcPath).Return(mockJwt, nil)
// run

286
pkg/vault/vault.go Normal file
View File

@ -0,0 +1,286 @@
package vault
import (
"encoding/json"
"fmt"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/hashicorp/vault/api"
"path"
"strconv"
"time"
)
// GetSecret uses the given path to fetch a secret from vault
func (c *Client) GetSecret(path string) (*api.Secret, error) {
return c.logical.Read(sanitizePath(path))
}
// GetKvSecret reads secret from the KV engine.
// It Automatically transforms the logical path to the HTTP API Path for the corresponding KV Engine version
func (c *Client) GetKvSecret(path string) (map[string]string, error) {
path = sanitizePath(path)
mountPath, version, err := c.getKvInfo(path)
if err != nil {
return nil, err
}
if version == 2 {
path = addPrefixToKvPath(path, mountPath, "data")
} else if version != 1 {
return nil, fmt.Errorf("KV Engine in version %d is currently not supported", version)
}
secret, err := c.GetSecret(path)
if secret == nil || err != nil {
return nil, err
}
var rawData interface{}
switch version {
case 1:
rawData = secret.Data
case 2:
var ok bool
rawData, ok = secret.Data["data"]
if !ok {
return nil, fmt.Errorf("missing 'data' field in response: %v", rawData)
}
}
data, ok := rawData.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("excpected 'data' field to be a map[string]interface{} but got %T instead", rawData)
}
secretData := make(map[string]string, len(data))
for k, v := range data {
switch t := v.(type) {
case string:
secretData[k] = t
case int:
secretData[k] = fmt.Sprintf("%d", t)
default:
jsonBytes, err := json.Marshal(t)
if err != nil {
log.Entry().Warnf("failed to parse Vault secret key %q, error: %s", k, err.Error())
continue
}
secretData[k] = string(jsonBytes)
}
}
return secretData, nil
}
// WriteKvSecret writes secret to kv engine
func (c *Client) WriteKvSecret(path string, newSecret map[string]string) error {
oldSecret, err := c.GetKvSecret(path)
if err != nil {
return err
}
secret := make(map[string]interface{}, len(oldSecret))
for k, v := range oldSecret {
secret[k] = v
}
for k, v := range newSecret {
secret[k] = v
}
path = sanitizePath(path)
mountPath, version, err := c.getKvInfo(path)
if err != nil {
return err
}
if version == 2 {
path = addPrefixToKvPath(path, mountPath, "data")
secret = map[string]interface{}{"data": secret}
} else if version != 1 {
return fmt.Errorf("KV Engine in version %d is currently not supported", version)
}
_, err = c.logical.Write(path, secret)
return err
}
// GenerateNewAppRoleSecret creates a new secret-id
func (c *Client) GenerateNewAppRoleSecret(secretID, appRoleName string) (string, error) {
appRolePath := c.getAppRolePath(appRoleName)
secretIDData, err := c.lookupSecretID(secretID, appRolePath)
if err != nil {
return "", err
}
reqPath := sanitizePath(path.Join(appRolePath, "/secret-id"))
// we preserve metadata which was attached to the secret-id
jsonBytes, err := json.Marshal(secretIDData["metadata"])
if err != nil {
return "", err
}
secret, err := c.logical.Write(reqPath, map[string]interface{}{
"metadata": string(jsonBytes),
})
if err != nil {
return "", err
}
if secret == nil || secret.Data == nil {
return "", fmt.Errorf("could not generate new approle secret-id for approle path %s", reqPath)
}
secretIDRaw, ok := secret.Data["secret_id"]
if !ok {
return "", fmt.Errorf("Vault response for path %s did not contain a new secret-id", reqPath)
}
newSecretID, ok := secretIDRaw.(string)
if !ok {
return "", fmt.Errorf("new secret-id from approle path %s has an unexpected type %T expected 'string'", reqPath, secretIDRaw)
}
return newSecretID, nil
}
// GetAppRoleSecretIDTtl returns the remaining time until the given secret-id expires
func (c *Client) GetAppRoleSecretIDTtl(secretID, roleName string) (time.Duration, error) {
appRolePath := c.getAppRolePath(roleName)
data, err := c.lookupSecretID(secretID, appRolePath)
if err != nil {
return 0, err
}
if data == nil || data["expiration_time"] == nil {
return 0, fmt.Errorf("could not load secret-id information from path %s", appRolePath)
}
expiration, ok := data["expiration_time"].(string)
if !ok || expiration == "" {
return 0, fmt.Errorf("could not handle get expiration time for secret-id from path %s", appRolePath)
}
expirationDate, err := time.Parse(time.RFC3339, expiration)
if err != nil {
return 0, err
}
ttl := expirationDate.Sub(time.Now())
if ttl < 0 {
return 0, nil
}
return ttl, nil
}
// RevokeToken revokes the token which is currently used.
// The client can't be used anymore after this function was called.
func (c *Client) RevokeToken() error {
_, err := c.logical.Write("auth/token/revoke-self", map[string]interface{}{})
return err
}
// MustRevokeToken same as RevokeToken but the program is terminated with an error if this fails.
// Should be used in defer statements only.
func (c *Client) MustRevokeToken() {
if err := c.RevokeToken(); err != nil {
log.Entry().WithError(err).Fatal("Could not revoke token")
}
}
// GetAppRoleName returns the AppRole role name which was used to authenticate.
// Returns "" when AppRole authentication wasn't used
func (c *Client) GetAppRoleName() (string, error) {
const lookupPath = "auth/token/lookup-self"
secret, err := c.GetSecret(lookupPath)
if err != nil {
return "", err
}
if secret.Data == nil {
return "", fmt.Errorf("could not lookup token information: %s", lookupPath)
}
meta, ok := secret.Data["meta"]
if !ok {
return "", fmt.Errorf("token info did not contain metadata %s", lookupPath)
}
metaMap, ok := meta.(map[string]interface{})
if !ok {
return "", fmt.Errorf("token info field 'meta' is not a map: %s", lookupPath)
}
roleName := metaMap["role_name"]
if roleName == nil {
return "", nil
}
roleNameStr, ok := roleName.(string)
if !ok {
// when AppRole authentication is not used vault admins can use the role_name field with other type
// so no error in this case
return "", nil
}
return roleNameStr, nil
}
func (c *Client) getAppRolePath(roleName string) string {
appRoleMountPoint := c.cfg.AppRoleMountPoint
if appRoleMountPoint == "" {
appRoleMountPoint = "auth/approle"
}
return path.Join(appRoleMountPoint, "role", roleName)
}
func (c *Client) getKvInfo(path string) (string, int, error) {
secret, err := c.GetSecret("sys/internal/ui/mounts/" + path)
if err != nil {
return "", 0, err
}
if secret == nil {
return "", 0, fmt.Errorf("failed to get version and engine mountpoint for path: %s", path)
}
var mountPath string
if mountPathRaw, ok := secret.Data["path"]; ok {
mountPath = mountPathRaw.(string)
}
options := secret.Data["options"]
if options == nil {
return mountPath, 1, nil
}
versionRaw := options.(map[string]interface{})["version"]
if versionRaw == nil {
return mountPath, 1, nil
}
version := versionRaw.(string)
if version == "" {
return mountPath, 1, nil
}
vNumber, err := strconv.Atoi(version)
if err != nil {
return mountPath, 0, err
}
return mountPath, vNumber, nil
}
func (c *Client) lookupSecretID(secretID, appRolePath string) (map[string]interface{}, error) {
reqPath := sanitizePath(path.Join(appRolePath, "/secret-id/lookup"))
secret, err := c.logical.Write(reqPath, map[string]interface{}{
"secret_id": secretID,
})
if err != nil {
return nil, err
}
return secret.Data, nil
}

View File

@ -30,7 +30,7 @@ const (
func TestGetKV2Secret(t *testing.T) {
t.Run("Test missing secret", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
setupMockKvV2(vaultMock)
vaultMock.On("Read", "secret/data/notexist").Return(nil, nil)
secret, err := client.GetKvSecret("secret/notexist")
@ -45,7 +45,7 @@ func TestGetKV2Secret(t *testing.T) {
t.Run("Getting secret from KV engine (v2)", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
setupMockKvV2(vaultMock)
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", secretAPIPath).Return(kv2Secret(SecretData{"key1": "value1", "key2": map[string]any{"subkey1": "subvalue2"}, "key3": 3, "key4": []string{"foo", "bar"}}), nil)
secret, err := client.GetKvSecret(secretName)
assert.NoError(t, err, "Expect GetKvSecret to succeed")
@ -58,7 +58,7 @@ func TestGetKV2Secret(t *testing.T) {
t.Run("error is thrown when data field is missing", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
setupMockKvV2(vaultMock)
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", secretAPIPath).Return(kv1Secret(SecretData{"key1": "value1"}), nil)
secret, err := client.GetKvSecret(secretName)
assert.Error(t, err, "Expected to fail since 'data' field is missing")
@ -74,7 +74,7 @@ func TestGetKV1Secret(t *testing.T) {
t.Run("Test missing secret", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
setupMockKvV1(vaultMock)
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", mock.AnythingOfType("string")).Return(nil, nil)
secret, err := client.GetKvSecret("secret/notexist")
@ -85,7 +85,7 @@ func TestGetKV1Secret(t *testing.T) {
t.Run("Test parsing KV1 secrets", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
setupMockKvV1(vaultMock)
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", secretName).Return(kv1Secret(SecretData{"key1": "value1", "key2": 5}), nil)
secret, err := client.GetKvSecret(secretName)
@ -103,7 +103,7 @@ func TestSecretIDGeneration(t *testing.T) {
t.Run("Test generating new secret-id", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
now := time.Now()
expiry := now.Add(5 * time.Hour).Format(time.RFC3339)
metadata := map[string]interface{}{
@ -128,7 +128,7 @@ func TestSecretIDGeneration(t *testing.T) {
t.Run("Test with no secret-id returned", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
now := time.Now()
expiry := now.Add(5 * time.Hour).Format(time.RFC3339)
metadata := map[string]interface{}{
@ -151,7 +151,7 @@ func TestSecretIDGeneration(t *testing.T) {
t.Run("Test with no new secret-id returned", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
now := time.Now()
expiry := now.Add(5 * time.Hour).Format(time.RFC3339)
metadata := map[string]interface{}{
@ -168,7 +168,7 @@ func TestSecretIDGeneration(t *testing.T) {
vaultMock.On("Write", path.Join(appRolePath, "/secret-id"), mapWith("metadata", string(metadataJSON))).Return(kv1Secret(nil), nil)
newSecretID, err := client.GenerateNewAppRoleSecret(secretID, appRoleName)
assert.EqualError(t, err, fmt.Sprintf("Could not generate new approle secret-id for approle path %s", path.Join(appRolePath, "secret-id")))
assert.EqualError(t, err, fmt.Sprintf("could not generate new approle secret-id for approle path %s", path.Join(appRolePath, "secret-id")))
assert.Equal(t, newSecretID, "")
})
}
@ -181,7 +181,7 @@ func TestSecretIDTtl(t *testing.T) {
t.Run("Test fetching secreID TTL", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
now := time.Now()
expiry := now.Add(5 * time.Hour).Format(time.RFC3339)
vaultMock.On("Write", path.Join(appRolePath, "secret-id/lookup"), mapWith("secret_id", secretID)).Return(kv1Secret(SecretData{
@ -195,16 +195,16 @@ func TestSecretIDTtl(t *testing.T) {
t.Run("Test with no expiration time", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Write", path.Join(appRolePath, "secret-id/lookup"), mapWith("secret_id", secretID)).Return(kv1Secret(SecretData{}), nil)
ttl, err := client.GetAppRoleSecretIDTtl(secretID, appRoleName)
assert.EqualError(t, err, fmt.Sprintf("Could not load secret-id information from path %s", appRolePath))
assert.EqualError(t, err, fmt.Sprintf("could not load secret-id information from path %s", appRolePath))
assert.Equal(t, time.Duration(0), ttl)
})
t.Run("Test with wrong date format", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Write", path.Join(appRolePath, "secret-id/lookup"), mapWith("secret_id", secretID)).Return(kv1Secret(SecretData{
"expiration_time": time.Now().String(),
}), nil)
@ -215,7 +215,7 @@ func TestSecretIDTtl(t *testing.T) {
t.Run("Test with expired secret-id", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
now := time.Now()
expiry := now.Add(-5 * time.Hour).Format(time.RFC3339)
vaultMock.On("Write", path.Join(appRolePath, "secret-id/lookup"), mapWith("secret_id", secretID)).Return(kv1Secret(SecretData{
@ -234,7 +234,7 @@ func TestGetAppRoleName(t *testing.T) {
t.Run("Test that correct role name is returned", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", "auth/token/lookup-self").Return(kv1Secret(SecretData{
"meta": SecretData{
"role_name": "test",
@ -248,27 +248,27 @@ func TestGetAppRoleName(t *testing.T) {
t.Run("Test without secret data", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", "auth/token/lookup-self").Return(kv1Secret(nil), nil)
appRoleName, err := client.GetAppRoleName()
assert.EqualError(t, err, "Could not lookup token information: auth/token/lookup-self")
assert.EqualError(t, err, "could not lookup token information: auth/token/lookup-self")
assert.Empty(t, appRoleName)
})
t.Run("Test without metadata data", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", "auth/token/lookup-self").Return(kv1Secret(SecretData{}), nil)
appRoleName, err := client.GetAppRoleName()
assert.EqualError(t, err, "Token info did not contain metadata auth/token/lookup-self")
assert.EqualError(t, err, "token info did not contain metadata auth/token/lookup-self")
assert.Empty(t, appRoleName)
})
t.Run("Test without role name in metadata", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", "auth/token/lookup-self").Return(kv1Secret(SecretData{
"meta": SecretData{},
}), nil)
@ -280,7 +280,7 @@ func TestGetAppRoleName(t *testing.T) {
t.Run("Test that different role_name types are ignored", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", "auth/token/lookup-self").Return(kv1Secret(SecretData{
"meta": SecretData{
"role_name": 5,
@ -297,7 +297,7 @@ func TestTokenRevocation(t *testing.T) {
t.Parallel()
t.Run("Test that revocation error is returned", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Write",
"auth/token/revoke-self",
mock.IsType(map[string]interface{}{})).Return(nil, errors.New("Test"))
@ -308,7 +308,7 @@ func TestTokenRevocation(t *testing.T) {
t.Run("Test that revocation endpoint is called", func(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Write",
"auth/token/revoke-self",
mock.IsType(map[string]interface{}{})).Return(nil, nil)
@ -319,7 +319,7 @@ func TestTokenRevocation(t *testing.T) {
func TestUnknownKvVersion(t *testing.T) {
vaultMock := &mocks.VaultMock{}
client := Client{vaultMock, &Config{}}
client := Client{nil, vaultMock, &ClientConfig{}}
vaultMock.On("Read", "sys/internal/ui/mounts/secret/secret").Return(&api.Secret{
Data: map[string]interface{}{
@ -335,15 +335,6 @@ func TestUnknownKvVersion(t *testing.T) {
}
func TestSetAppRoleMountPont(t *testing.T) {
client := Client{nil, &Config{}}
const newMountpoint = "auth/test"
client.SetAppRoleMountPoint("auth/test")
assert.Equal(t, newMountpoint, client.config.AppRoleMountPoint)
}
func setupMockKvV2(vaultMock *mocks.VaultMock) {
vaultMock.On("Read", mock.MatchedBy(func(path string) bool {
return strings.HasPrefix(path, sysLookupPath)