From f9190520c79de54182c6090679fd07a436ee54f5 Mon Sep 17 00:00:00 2001 From: gr0 Date: Mon, 22 May 2023 18:40:38 +0200 Subject: [PATCH 01/23] feat: add GCP secrect manager support - the code handling GCP integration Signed-off-by: gr0 --- app/controlplane/internal/conf/conf.pb.go | 2 +- go.mod | 12 +- go.sum | 13 ++ .../gcp/mocks/SecretsManagerInterface.go | 200 ++++++++++++++++++ internal/credentials/gcp/secretmanager.go | 151 +++++++++++++ .../credentials/gcp/secretmanager_test.go | 112 ++++++++++ 6 files changed, 487 insertions(+), 3 deletions(-) create mode 100644 internal/credentials/gcp/mocks/SecretsManagerInterface.go create mode 100644 internal/credentials/gcp/secretmanager.go create mode 100644 internal/credentials/gcp/secretmanager_test.go diff --git a/app/controlplane/internal/conf/conf.pb.go b/app/controlplane/internal/conf/conf.pb.go index 6b8dee8b7..ee9ddb42d 100644 --- a/app/controlplane/internal/conf/conf.pb.go +++ b/app/controlplane/internal/conf/conf.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 +// protoc-gen-go v1.30.0 // protoc (unknown) // source: conf.proto diff --git a/go.mod b/go.mod index 128f48c18..f6edf8003 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/coreos/go-oidc/v3 v3.5.0 github.com/docker/distribution v2.8.2+incompatible github.com/docker/go-connections v0.4.0 - github.com/envoyproxy/protoc-gen-validate v0.9.1 + github.com/envoyproxy/protoc-gen-validate v0.10.0 github.com/getsentry/sentry-go v0.17.0 github.com/go-kratos/kratos/contrib/log/zap/v2 v2.0.0-20230113095809-bebea0c103a8 github.com/go-kratos/kratos/v2 v2.5.3 @@ -56,7 +56,7 @@ require ( golang.org/x/oauth2 v0.7.0 golang.org/x/term v0.7.0 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 - google.golang.org/grpc v1.54.0 + google.golang.org/grpc v1.55.0 google.golang.org/protobuf v1.30.0 sigs.k8s.io/yaml v1.3.0 ) @@ -65,6 +65,8 @@ require ( ariga.io/atlas v0.9.1 // indirect cloud.google.com/go/compute v1.19.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v0.13.0 // indirect + cloud.google.com/go/secretmanager v1.10.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.28 // indirect @@ -124,6 +126,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.12.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/certificate-transparency-go v1.1.4 // indirect @@ -132,7 +135,10 @@ require ( github.com/google/go-github/v50 v50.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/s2a-go v0.1.2 // indirect github.com/google/trillian v1.5.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -210,6 +216,7 @@ require ( github.com/xanzy/go-gitlab v0.83.0 // indirect github.com/zclconf/go-cty v1.8.0 // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect + go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect go.uber.org/atomic v1.10.0 // indirect @@ -222,6 +229,7 @@ require ( golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.7.0 // indirect + google.golang.org/api v0.119.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index dd9f18c15..8ca7789ea 100644 --- a/go.sum +++ b/go.sum @@ -48,11 +48,14 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= cloud.google.com/go/kms v1.10.1 h1:7hm1bRqGCA1GBRQUrp831TwJ9TWhP+tvLuP497CQS2g= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/secretmanager v1.10.1 h1:9QwQ3oMurvmPEmM80spGe2SFGDa+RRgkLIdTm3gMWO8= +cloud.google.com/go/secretmanager v1.10.1/go.mod h1:pxG0NLpcK6OMy54kfZgQmsKTPxJem708X1es7xv8n60= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= @@ -305,6 +308,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= +github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg= github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8= @@ -556,6 +561,7 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.2 h1:WVtYAYuYxKeYajAmThMRYWP6K3wXkcqbGHeUgeubUHY= +github.com/google/s2a-go v0.1.2/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= @@ -569,11 +575,13 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -1191,6 +1199,7 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= @@ -1643,6 +1652,7 @@ google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUb google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/api v0.119.0 h1:Dzq+ARD6+8jmd5wknJE1crpuzu1JiovEU6gCp9PkoKA= +google.golang.org/api v0.119.0/go.mod h1:CrSvlNEFCFLae9ZUtL1z+61+rEBD7J/aCYwVYKZoWFU= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1757,10 +1767,13 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/internal/credentials/gcp/mocks/SecretsManagerInterface.go b/internal/credentials/gcp/mocks/SecretsManagerInterface.go new file mode 100644 index 000000000..4102b7c03 --- /dev/null +++ b/internal/credentials/gcp/mocks/SecretsManagerInterface.go @@ -0,0 +1,200 @@ +// Code generated by mockery v2.20.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + + gax "github.com/googleapis/gax-go/v2" + + mock "github.com/stretchr/testify/mock" + + secretmanagerpb "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" +) + +// SecretsManagerInterface is an autogenerated mock type for the SecretsManagerInterface type +type SecretsManagerInterface struct { + mock.Mock +} + +// AccessSecretVersion provides a mock function with given fields: ctx, req, opts +func (_m *SecretsManagerInterface) AccessSecretVersion(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, req) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *secretmanagerpb.AccessSecretVersionResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.AccessSecretVersionRequest, ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error)); ok { + return rf(ctx, req, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.AccessSecretVersionRequest, ...gax.CallOption) *secretmanagerpb.AccessSecretVersionResponse); ok { + r0 = rf(ctx, req, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*secretmanagerpb.AccessSecretVersionResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *secretmanagerpb.AccessSecretVersionRequest, ...gax.CallOption) error); ok { + r1 = rf(ctx, req, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AddSecretVersion provides a mock function with given fields: ctx, req, opts +func (_m *SecretsManagerInterface) AddSecretVersion(ctx context.Context, req *secretmanagerpb.AddSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.SecretVersion, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, req) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *secretmanagerpb.SecretVersion + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.AddSecretVersionRequest, ...gax.CallOption) (*secretmanagerpb.SecretVersion, error)); ok { + return rf(ctx, req, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.AddSecretVersionRequest, ...gax.CallOption) *secretmanagerpb.SecretVersion); ok { + r0 = rf(ctx, req, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*secretmanagerpb.SecretVersion) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *secretmanagerpb.AddSecretVersionRequest, ...gax.CallOption) error); ok { + r1 = rf(ctx, req, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Close provides a mock function with given fields: +func (_m *SecretsManagerInterface) Close() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreateSecret provides a mock function with given fields: ctx, req, opts +func (_m *SecretsManagerInterface) CreateSecret(ctx context.Context, req *secretmanagerpb.CreateSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, req) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *secretmanagerpb.Secret + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.CreateSecretRequest, ...gax.CallOption) (*secretmanagerpb.Secret, error)); ok { + return rf(ctx, req, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.CreateSecretRequest, ...gax.CallOption) *secretmanagerpb.Secret); ok { + r0 = rf(ctx, req, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*secretmanagerpb.Secret) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *secretmanagerpb.CreateSecretRequest, ...gax.CallOption) error); ok { + r1 = rf(ctx, req, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeleteSecret provides a mock function with given fields: ctx, req, opts +func (_m *SecretsManagerInterface) DeleteSecret(ctx context.Context, req *secretmanagerpb.DeleteSecretRequest, opts ...gax.CallOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, req) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.DeleteSecretRequest, ...gax.CallOption) error); ok { + r0 = rf(ctx, req, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetSecret provides a mock function with given fields: ctx, req, opts +func (_m *SecretsManagerInterface) GetSecret(ctx context.Context, req *secretmanagerpb.GetSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, req) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *secretmanagerpb.Secret + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.GetSecretRequest, ...gax.CallOption) (*secretmanagerpb.Secret, error)); ok { + return rf(ctx, req, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *secretmanagerpb.GetSecretRequest, ...gax.CallOption) *secretmanagerpb.Secret); ok { + r0 = rf(ctx, req, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*secretmanagerpb.Secret) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *secretmanagerpb.GetSecretRequest, ...gax.CallOption) error); ok { + r1 = rf(ctx, req, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewSecretsManagerInterface interface { + mock.TestingT + Cleanup(func()) +} + +// NewSecretsManagerInterface creates a new instance of SecretsManagerInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewSecretsManagerInterface(t mockConstructorTestingTNewSecretsManagerInterface) *SecretsManagerInterface { + mock := &SecretsManagerInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go new file mode 100644 index 000000000..92a15d98f --- /dev/null +++ b/internal/credentials/gcp/secretmanager.go @@ -0,0 +1,151 @@ +package gcp + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "strings" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "google.golang.org/api/option" + + "github.com/chainloop-dev/chainloop/internal/credentials" + "github.com/chainloop-dev/chainloop/internal/servicelogger" + "github.com/docker/distribution/uuid" + "github.com/go-kratos/kratos/v2/log" + "github.com/googleapis/gax-go/v2" +) + +type SecretsManagerInterface interface { + CreateSecret(ctx context.Context, req *secretmanagerpb.CreateSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) + AddSecretVersion(ctx context.Context, req *secretmanagerpb.AddSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.SecretVersion, error) + AccessSecretVersion(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) + DeleteSecret(ctx context.Context, req *secretmanagerpb.DeleteSecretRequest, opts ...gax.CallOption) error + GetSecret(ctx context.Context, req *secretmanagerpb.GetSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) + Close() error +} + +type Manager struct { + projectID string + client SecretsManagerInterface + logger *log.Helper +} + +type NewManagerOpts struct { + ProjectID, AuthKey string + Logger log.Logger +} + +func NewManager(opts *NewManagerOpts) (*Manager, error) { + if opts.ProjectID == "" || opts.AuthKey == "" { + return nil, errors.New("projectID and authKey are required") + } + + l := opts.Logger + if l == nil { + l = log.NewStdLogger(io.Discard) + } + + logger := servicelogger.ScopedHelper(l, "credentials/gcp-secrets-manager") + logger.Infow("msg", "configuring gcp secrets-manager", "projectID", opts.ProjectID) + + cli, err := secretmanager.NewRESTClient(context.TODO(), option.WithCredentialsJSON([]byte(opts.AuthKey))) + if err != nil { + return nil, fmt.Errorf("error while connecting to the project: %v", err) + } + + return &Manager{ + projectID: opts.ProjectID, + client: cli, + logger: logger, + }, nil +} + +// SaveCredentials saves credentials +func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) (string, error) { + secretID := strings.Join([]string{orgID, uuid.Generate().String()}, "-") + + // first create the secret itself + createSecretReq := &secretmanagerpb.CreateSecretRequest{ + Parent: fmt.Sprintf("projects/%s", m.projectID), + SecretId: secretID, + Secret: &secretmanagerpb.Secret{ + Replication: &secretmanagerpb.Replication{ + Replication: &secretmanagerpb.Replication_Automatic_{ + Automatic: &secretmanagerpb.Replication_Automatic{}, + }, + }, + }, + } + secret, err := m.client.CreateSecret(ctx, createSecretReq) + if err != nil { + return "", fmt.Errorf("creating secret in GCP: %w", err) + } + + // store creds in key-value pair + c, err := json.Marshal(creds) + if err != nil { + return "", fmt.Errorf("marshaling credentials to be stored: %w", err) + } + + // once the secret is created store it as the newest version + addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ + Parent: secret.Name, + Payload: &secretmanagerpb.SecretPayload{ + Data: c, + }, + } + _, err = m.client.AddSecretVersion(ctx, addSecretVersionReq) + if err != nil { + return "", fmt.Errorf("creating secret version in GCP: %w", err) + } + + return secretID, nil +} + +// ReadCredentials reads the latest version of the credentials +func (m *Manager) ReadCredentials(ctx context.Context, secretID string, creds any) error { + getSecretRequest := secretmanagerpb.AccessSecretVersionRequest{ + Name: fmt.Sprintf("projects/%v/secrets/%v/versions/latest", m.projectID, secretID), + } + + result, err := m.client.AccessSecretVersion(ctx, &getSecretRequest) + if err != nil { + return fmt.Errorf("%w: path=%s", credentials.ErrNotFound, secretID) + } + + return json.Unmarshal(result.Payload.Data, creds) +} + +// DeleteCredentials deletes credentials and versions +func (m *Manager) DeleteCredentials(ctx context.Context, secretID string) error { + if m.secretExists(ctx, secretID) { + deleteRequest := secretmanagerpb.DeleteSecretRequest{ + Name: fmt.Sprintf("projects/%v/secrets/%v", m.projectID, secretID), + } + + return m.client.DeleteSecret(ctx, &deleteRequest) + } + + return fmt.Errorf("%w: path=%s", credentials.ErrNotFound, secretID) +} + +func (c *Manager) secretExists(ctx context.Context, secretID string) bool { + accessRequest := secretmanagerpb.GetSecretRequest{ + Name: fmt.Sprintf("projects/%v/secrets/%v", c.projectID, secretID), + } + + _, err := c.client.GetSecret(ctx, &accessRequest) + return err == nil +} + +// Close closes the manager +func (m *Manager) Close() error { + if m.client == nil { + return nil + } + return m.client.Close() +} diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go new file mode 100644 index 000000000..85c5e299b --- /dev/null +++ b/internal/credentials/gcp/secretmanager_test.go @@ -0,0 +1,112 @@ +package gcp + +import ( + "context" + "encoding/json" + "testing" + + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "github.com/chainloop-dev/chainloop/internal/credentials" + gcpmocks "github.com/chainloop-dev/chainloop/internal/credentials/gcp/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +const defaultOrgID = "test-org" +const defaultProjectID = "1234-5678-9012" +const defaultAccessKey string = `{ + "type": "service_account", + "project_id": "chainloop-test-dev", + "private_key_id": "12345123451234512345", + "private_key": "-----BEGIN PRIVATE KEY-----\nAAABBB\n-----END PRIVATE KEY-----\n", + "client_email": "chainloop-dev@chainloop-dev.iam.gserviceaccount.com", + "client_id": "5678567856781234", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/chainloop-dev%40chainloop-dev.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +}` + +func TestNewManager(t *testing.T) { + assert := assert.New(t) + + testCases := []struct { + name string + projectID string + authKey string + expectedError bool + }{ + {name: "missing projectID", projectID: "", authKey: defaultAccessKey, expectedError: true}, + {name: "missing authKey", projectID: defaultProjectID, authKey: "", expectedError: true}, + {name: "valid manager", projectID: defaultProjectID, authKey: defaultAccessKey}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + opts := &NewManagerOpts{ProjectID: tc.projectID, AuthKey: tc.authKey} + _, err := NewManager(opts) + if tc.expectedError { + assert.Error(err) + } else { + assert.NoError(err) + } + }) + } +} + +func TestCreateCredentials(t *testing.T) { + ociCreds := &credentials.OCIKeypair{Repo: "repo", Username: "user", Password: "password"} + creds, err := json.Marshal(ociCreds) + assert.NoError(t, err) + + ctx := context.Background() + m := &Manager{} + clientMock := gcpmocks.NewSecretsManagerInterface(t) + m.client = clientMock + + clientMock.On("CreateSecret", ctx, mock.Anything).Return(&secretmanagerpb.Secret{}, nil).Once() + clientMock.On("AddSecretVersion", ctx, mock.Anything).Return(&secretmanagerpb.SecretVersion{}, nil) + + _, err = m.SaveCredentials(ctx, defaultOrgID, creds) + assert.NoError(t, err) +} + +func TestReadCredentials(t *testing.T) { + ctx := context.Background() + m := &Manager{} + clientMock := gcpmocks.NewSecretsManagerInterface(t) + m.client = clientMock + secretId := "some-secret-id" + + validAPICreds := &credentials.APICreds{Host: "host", Key: "key"} + payload, err := json.Marshal(validAPICreds) + assert.NoError(t, err) + + clientMock.On("AccessSecretVersion", ctx, mock.Anything).Return(&secretmanagerpb.AccessSecretVersionResponse{ + Name: secretId, + Payload: &secretmanagerpb.SecretPayload{ + Data: payload, + }, + }, nil).Once() + + creds := &credentials.APICreds{} + err = m.ReadCredentials(ctx, secretId, creds) + assert.NoError(t, err) + assert.Equal(t, "host", creds.Host) + assert.Equal(t, "key", creds.Key) +} + +func TestDeleteCredentials(t *testing.T) { + m := &Manager{} + clientMock := gcpmocks.NewSecretsManagerInterface(t) + m.client = clientMock + m.projectID = defaultProjectID + secretId := "some-secret-id" + + clientMock.On("GetSecret", mock.Anything, mock.Anything).Return(&secretmanagerpb.Secret{}, nil).Once() + clientMock.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) + + err := m.DeleteCredentials(context.Background(), secretId) + assert.NoError(t, err) +} From 5fd5faabc430efadec4088993fba850264f84c9a Mon Sep 17 00:00:00 2001 From: gr0 Date: Mon, 22 May 2023 18:45:17 +0200 Subject: [PATCH 02/23] feat: add GCP secrect manager support - CLI support for controlplane Signed-off-by: gr0 --- app/artifact-cas/internal/conf/conf.proto | 6 + app/controlplane/cmd/main.go | 24 +++ app/controlplane/internal/conf/conf.pb.go | 184 +++++++++++++----- .../internal/conf/conf.pb.validate.go | 148 ++++++++++++++ app/controlplane/internal/conf/conf.proto | 6 + 5 files changed, 323 insertions(+), 45 deletions(-) diff --git a/app/artifact-cas/internal/conf/conf.proto b/app/artifact-cas/internal/conf/conf.proto index ff2e7ec31..6b2cbb3c7 100644 --- a/app/artifact-cas/internal/conf/conf.proto +++ b/app/artifact-cas/internal/conf/conf.proto @@ -66,6 +66,7 @@ message Credentials { oneof backend { AWSSecretManager aws_secret_manager = 1; Vault vault = 2; + GCPSecretManager gcp_secret_manager = 3; } // Top level is deprecated now @@ -88,4 +89,9 @@ message Credentials { // mount path of the kv engine, default /secret string mount_path = 3; } + + message GCPSecretManager { + string project_id = 1; + string auth_key = 2; + } } \ No newline at end of file diff --git a/app/controlplane/cmd/main.go b/app/controlplane/cmd/main.go index 2b901dbd5..36e8e44bb 100644 --- a/app/controlplane/cmd/main.go +++ b/app/controlplane/cmd/main.go @@ -30,6 +30,7 @@ import ( "github.com/chainloop-dev/chainloop/app/controlplane/internal/server" "github.com/chainloop-dev/chainloop/internal/credentials" awssecrets "github.com/chainloop-dev/chainloop/internal/credentials/aws" + "github.com/chainloop-dev/chainloop/internal/credentials/gcp" "github.com/chainloop-dev/chainloop/internal/credentials/vault" "github.com/chainloop-dev/chainloop/internal/servicelogger" @@ -166,6 +167,10 @@ func newCredentialsWriter(conf *conf.Bootstrap, l log.Logger) (credentials.Reade if c := credsConfig.GetVault(); c != nil { return newVaultCredentialsManager(c, l) } + + if c := credsConfig.GetGcpSecretManager(); c != nil { + return newGCPCredentialsManager(c, l) + } } return nil, errors.New("no credentials manager configured") @@ -212,6 +217,25 @@ func newVaultCredentialsManager(conf *conf.Credentials_Vault, l log.Logger) (*va return m, nil } +func newGCPCredentialsManager(conf *conf.Credentials_GCPSecretManager, l log.Logger) (*gcp.Manager, error) { + if conf == nil { + return nil, errors.New("uncompleted configuration for GCP secret manager") + } + + opts := &gcp.NewManagerOpts{ + ProjectID: conf.ProjectId, + AuthKey: conf.AuthKey, + Logger: l, + } + + m, err := gcp.NewManager(opts) + if err != nil { + return nil, fmt.Errorf("configuring the GCP secret manager: %w", err) + } + + return m, nil +} + func initSentry(c *conf.Bootstrap, logger log.Logger) (cleanupFunc func(), err error) { cleanupFunc = func() { sentry.Flush(2 * time.Second) diff --git a/app/controlplane/internal/conf/conf.pb.go b/app/controlplane/internal/conf/conf.pb.go index ee9ddb42d..a6cc65a0c 100644 --- a/app/controlplane/internal/conf/conf.pb.go +++ b/app/controlplane/internal/conf/conf.pb.go @@ -317,6 +317,7 @@ type Credentials struct { // // *Credentials_AwsSecretManager // *Credentials_Vault_ + // *Credentials_GcpSecretManager Backend isCredentials_Backend `protobuf_oneof:"backend"` } @@ -373,6 +374,13 @@ func (x *Credentials) GetVault() *Credentials_Vault { return nil } +func (x *Credentials) GetGcpSecretManager() *Credentials_GCPSecretManager { + if x, ok := x.GetBackend().(*Credentials_GcpSecretManager); ok { + return x.GcpSecretManager + } + return nil +} + type isCredentials_Backend interface { isCredentials_Backend() } @@ -385,10 +393,16 @@ type Credentials_Vault_ struct { Vault *Credentials_Vault `protobuf:"bytes,2,opt,name=vault,proto3,oneof"` } +type Credentials_GcpSecretManager struct { + GcpSecretManager *Credentials_GCPSecretManager `protobuf:"bytes,3,opt,name=gcp_secret_manager,json=gcpSecretManager,proto3,oneof"` +} + func (*Credentials_AwsSecretManager) isCredentials_Backend() {} func (*Credentials_Vault_) isCredentials_Backend() {} +func (*Credentials_GcpSecretManager) isCredentials_Backend() {} + type Bootstrap_Observability struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -949,6 +963,61 @@ func (x *Credentials_Vault) GetSecretPrefix() string { return "" } +type Credentials_GCPSecretManager struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` +} + +func (x *Credentials_GCPSecretManager) Reset() { + *x = Credentials_GCPSecretManager{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Credentials_GCPSecretManager) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Credentials_GCPSecretManager) ProtoMessage() {} + +func (x *Credentials_GCPSecretManager) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Credentials_GCPSecretManager.ProtoReflect.Descriptor instead. +func (*Credentials_GCPSecretManager) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{4, 2} +} + +func (x *Credentials_GCPSecretManager) GetProjectId() string { + if x != nil { + return x.ProjectId + } + return "" +} + +func (x *Credentials_GCPSecretManager) GetAuthKey() string { + if x != nil { + return x.AuthKey + } + return "" +} + type Credentials_AWSSecretManager_Creds struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -961,7 +1030,7 @@ type Credentials_AWSSecretManager_Creds struct { func (x *Credentials_AWSSecretManager_Creds) Reset() { *x = Credentials_AWSSecretManager_Creds{} if protoimpl.UnsafeEnabled { - mi := &file_conf_proto_msgTypes[14] + mi := &file_conf_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -974,7 +1043,7 @@ func (x *Credentials_AWSSecretManager_Creds) String() string { func (*Credentials_AWSSecretManager_Creds) ProtoMessage() {} func (x *Credentials_AWSSecretManager_Creds) ProtoReflect() protoreflect.Message { - mi := &file_conf_proto_msgTypes[14] + mi := &file_conf_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1096,7 +1165,7 @@ var file_conf_proto_rawDesc = []byte{ 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, - 0x22, 0xe4, 0x03, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x22, 0x81, 0x05, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4d, 0x0a, 0x12, 0x61, 0x77, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, @@ -1104,34 +1173,44 @@ var file_conf_proto_rawDesc = []byte{ 0x77, 0x73, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x56, 0x61, 0x75, - 0x6c, 0x74, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x1a, 0xd1, 0x01, 0x0a, 0x10, - 0x41, 0x57, 0x53, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x12, 0x39, 0x0a, 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, - 0x53, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, - 0x72, 0x65, 0x64, 0x73, 0x52, 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, - 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, - 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0x45, 0x0a, 0x05, 0x43, 0x72, 0x65, 0x64, - 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, - 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x1a, - 0x7b, 0x0a, 0x05, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x09, 0x0a, 0x07, - 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, - 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, - 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, - 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x74, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x4d, 0x0a, 0x12, 0x67, + 0x63, 0x70, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x67, 0x63, 0x70, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x1a, 0xd1, 0x01, 0x0a, 0x10, 0x41, + 0x57, 0x53, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, + 0x39, 0x0a, 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x72, + 0x65, 0x64, 0x73, 0x52, 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, + 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0x45, 0x0a, 0x05, 0x43, 0x72, 0x65, 0x64, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, + 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x1a, 0x7b, + 0x0a, 0x05, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0x4c, 0x0a, 0x10, 0x47, + 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, + 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x19, + 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x63, + 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, + 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1146,7 +1225,7 @@ func file_conf_proto_rawDescGZIP() []byte { return file_conf_proto_rawDescData } -var file_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_conf_proto_goTypes = []interface{}{ (*Bootstrap)(nil), // 0: Bootstrap (*Server)(nil), // 1: Server @@ -1162,8 +1241,9 @@ var file_conf_proto_goTypes = []interface{}{ (*Auth_OIDC)(nil), // 11: Auth.OIDC (*Credentials_AWSSecretManager)(nil), // 12: Credentials.AWSSecretManager (*Credentials_Vault)(nil), // 13: Credentials.Vault - (*Credentials_AWSSecretManager_Creds)(nil), // 14: Credentials.AWSSecretManager.Creds - (*durationpb.Duration)(nil), // 15: google.protobuf.Duration + (*Credentials_GCPSecretManager)(nil), // 14: Credentials.GCPSecretManager + (*Credentials_AWSSecretManager_Creds)(nil), // 15: Credentials.AWSSecretManager.Creds + (*durationpb.Duration)(nil), // 16: google.protobuf.Duration } var file_conf_proto_depIdxs = []int32{ 1, // 0: Bootstrap.server:type_name -> Server @@ -1179,16 +1259,17 @@ var file_conf_proto_depIdxs = []int32{ 11, // 10: Auth.oidc:type_name -> Auth.OIDC 12, // 11: Credentials.aws_secret_manager:type_name -> Credentials.AWSSecretManager 13, // 12: Credentials.vault:type_name -> Credentials.Vault - 7, // 13: Bootstrap.Observability.sentry:type_name -> Bootstrap.Observability.Sentry - 9, // 14: Bootstrap.CASServer.grpc:type_name -> Server.GRPC - 15, // 15: Server.HTTP.timeout:type_name -> google.protobuf.Duration - 15, // 16: Server.GRPC.timeout:type_name -> google.protobuf.Duration - 14, // 17: Credentials.AWSSecretManager.creds:type_name -> Credentials.AWSSecretManager.Creds - 18, // [18:18] is the sub-list for method output_type - 18, // [18:18] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 14, // 13: Credentials.gcp_secret_manager:type_name -> Credentials.GCPSecretManager + 7, // 14: Bootstrap.Observability.sentry:type_name -> Bootstrap.Observability.Sentry + 9, // 15: Bootstrap.CASServer.grpc:type_name -> Server.GRPC + 16, // 16: Server.HTTP.timeout:type_name -> google.protobuf.Duration + 16, // 17: Server.GRPC.timeout:type_name -> google.protobuf.Duration + 15, // 18: Credentials.AWSSecretManager.creds:type_name -> Credentials.AWSSecretManager.Creds + 19, // [19:19] is the sub-list for method output_type + 19, // [19:19] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name } func init() { file_conf_proto_init() } @@ -1366,6 +1447,18 @@ func file_conf_proto_init() { } } file_conf_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Credentials_GCPSecretManager); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Credentials_AWSSecretManager_Creds); i { case 0: return &v.state @@ -1381,6 +1474,7 @@ func file_conf_proto_init() { file_conf_proto_msgTypes[4].OneofWrappers = []interface{}{ (*Credentials_AwsSecretManager)(nil), (*Credentials_Vault_)(nil), + (*Credentials_GcpSecretManager)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -1388,7 +1482,7 @@ func file_conf_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_conf_proto_rawDesc, NumEnums: 0, - NumMessages: 15, + NumMessages: 16, NumExtensions: 0, NumServices: 0, }, diff --git a/app/controlplane/internal/conf/conf.pb.validate.go b/app/controlplane/internal/conf/conf.pb.validate.go index 79bb5e448..e7bcbd277 100644 --- a/app/controlplane/internal/conf/conf.pb.validate.go +++ b/app/controlplane/internal/conf/conf.pb.validate.go @@ -856,6 +856,47 @@ func (m *Credentials) validate(all bool) error { } } + case *Credentials_GcpSecretManager: + if v == nil { + err := CredentialsValidationError{ + field: "Backend", + reason: "oneof value cannot be a typed-nil", + } + if !all { + return err + } + errors = append(errors, err) + } + + if all { + switch v := interface{}(m.GetGcpSecretManager()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CredentialsValidationError{ + field: "GcpSecretManager", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CredentialsValidationError{ + field: "GcpSecretManager", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetGcpSecretManager()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CredentialsValidationError{ + field: "GcpSecretManager", + reason: "embedded message failed validation", + cause: err, + } + } + } + default: _ = v // ensures v is used } @@ -2051,6 +2092,113 @@ var _ interface { ErrorName() string } = Credentials_VaultValidationError{} +// Validate checks the field values on Credentials_GCPSecretManager with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *Credentials_GCPSecretManager) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Credentials_GCPSecretManager with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// Credentials_GCPSecretManagerMultiError, or nil if none found. +func (m *Credentials_GCPSecretManager) ValidateAll() error { + return m.validate(true) +} + +func (m *Credentials_GCPSecretManager) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for ProjectId + + // no validation rules for AuthKey + + if len(errors) > 0 { + return Credentials_GCPSecretManagerMultiError(errors) + } + + return nil +} + +// Credentials_GCPSecretManagerMultiError is an error wrapping multiple +// validation errors returned by Credentials_GCPSecretManager.ValidateAll() if +// the designated constraints aren't met. +type Credentials_GCPSecretManagerMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m Credentials_GCPSecretManagerMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m Credentials_GCPSecretManagerMultiError) AllErrors() []error { return m } + +// Credentials_GCPSecretManagerValidationError is the validation error returned +// by Credentials_GCPSecretManager.Validate if the designated constraints +// aren't met. +type Credentials_GCPSecretManagerValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e Credentials_GCPSecretManagerValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e Credentials_GCPSecretManagerValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e Credentials_GCPSecretManagerValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e Credentials_GCPSecretManagerValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e Credentials_GCPSecretManagerValidationError) ErrorName() string { + return "Credentials_GCPSecretManagerValidationError" +} + +// Error satisfies the builtin error interface +func (e Credentials_GCPSecretManagerValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sCredentials_GCPSecretManager.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = Credentials_GCPSecretManagerValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = Credentials_GCPSecretManagerValidationError{} + // Validate checks the field values on Credentials_AWSSecretManager_Creds with // the rules defined in the proto definition for this message. If any rules // are violated, the first error encountered is returned, or nil if there are diff --git a/app/controlplane/internal/conf/conf.proto b/app/controlplane/internal/conf/conf.proto index 16a711415..26336144f 100644 --- a/app/controlplane/internal/conf/conf.proto +++ b/app/controlplane/internal/conf/conf.proto @@ -95,6 +95,7 @@ message Credentials { oneof backend { AWSSecretManager aws_secret_manager = 1; Vault vault = 2; + GCPSecretManager gcp_secret_manager = 3; } // Top level is deprecated now @@ -119,4 +120,9 @@ message Credentials { string mount_path = 3; string secret_prefix = 4; } + + message GCPSecretManager { + string project_id = 1; + string auth_key = 2; + } } \ No newline at end of file From 0d8c81bd1f8be6fdb25dace695795e47b69a603f Mon Sep 17 00:00:00 2001 From: gr0 Date: Mon, 22 May 2023 18:49:32 +0200 Subject: [PATCH 03/23] feat: add GCP secrect manager support - support for artifact-cas Signed-off-by: gr0 --- app/artifact-cas/cmd/main.go | 30 +++- app/artifact-cas/internal/conf/conf.pb.go | 176 +++++++++++++++++----- 2 files changed, 162 insertions(+), 44 deletions(-) diff --git a/app/artifact-cas/cmd/main.go b/app/artifact-cas/cmd/main.go index 8dad12cea..f571bb513 100644 --- a/app/artifact-cas/cmd/main.go +++ b/app/artifact-cas/cmd/main.go @@ -24,6 +24,7 @@ import ( "github.com/chainloop-dev/chainloop/internal/credentials" awssecrets "github.com/chainloop-dev/chainloop/internal/credentials/aws" + "github.com/chainloop-dev/chainloop/internal/credentials/gcp" "github.com/chainloop-dev/chainloop/internal/credentials/vault" "github.com/getsentry/sentry-go" @@ -125,10 +126,10 @@ func main() { } func newCredentialsReader(conf *conf.Credentials, l log.Logger) (credentials.Reader, error) { - awsc, vaultc := conf.GetAwsSecretManager(), conf.GetVault() - if awsc == nil && vaultc == nil { + awsc, vaultc, gcpc := conf.GetAwsSecretManager(), conf.GetVault(), conf.GetGcpSecretManager() + if awsc == nil && vaultc == nil && gcpc == nil { return nil, errors.New("no credentials manager configuration found") - } else if awsc != nil && vaultc != nil { + } else if awsc != nil && vaultc != nil && gcpc != nil { return nil, errors.New("only one credentials manager can be configured") } @@ -136,6 +137,10 @@ func newCredentialsReader(conf *conf.Credentials, l log.Logger) (credentials.Rea return newAWSCredentialsManager(c, l) } + if c := conf.GetGcpSecretManager(); c != nil { + return newGCPCredentialsManager(c, l) + } + return newVaultCredentialsManager(conf.GetVault(), l) } @@ -180,6 +185,25 @@ func newVaultCredentialsManager(conf *conf.Credentials_Vault, l log.Logger) (*va return m, nil } +func newGCPCredentialsManager(conf *conf.Credentials_GCPSecretManager, l log.Logger) (*gcp.Manager, error) { + if conf == nil { + return nil, errors.New("uncompleted configuration for GCP secret manager") + } + + opts := &gcp.NewManagerOpts{ + ProjectID: conf.ProjectId, + AuthKey: conf.AuthKey, + Logger: l, + } + + m, err := gcp.NewManager(opts) + if err != nil { + return nil, fmt.Errorf("configuring the GCP secret manager: %w", err) + } + + return m, nil +} + func initSentry(c *conf.Bootstrap, logger log.Logger) (cleanupFunc func(), err error) { cleanupFunc = func() { sentry.Flush(2 * time.Second) diff --git a/app/artifact-cas/internal/conf/conf.pb.go b/app/artifact-cas/internal/conf/conf.pb.go index 98e918632..22db85538 100644 --- a/app/artifact-cas/internal/conf/conf.pb.go +++ b/app/artifact-cas/internal/conf/conf.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 +// protoc-gen-go v1.30.0 // protoc (unknown) // source: conf.proto @@ -232,6 +232,7 @@ type Credentials struct { // // *Credentials_AwsSecretManager // *Credentials_Vault_ + // *Credentials_GcpSecretManager Backend isCredentials_Backend `protobuf_oneof:"backend"` } @@ -288,6 +289,13 @@ func (x *Credentials) GetVault() *Credentials_Vault { return nil } +func (x *Credentials) GetGcpSecretManager() *Credentials_GCPSecretManager { + if x, ok := x.GetBackend().(*Credentials_GcpSecretManager); ok { + return x.GcpSecretManager + } + return nil +} + type isCredentials_Backend interface { isCredentials_Backend() } @@ -300,10 +308,16 @@ type Credentials_Vault_ struct { Vault *Credentials_Vault `protobuf:"bytes,2,opt,name=vault,proto3,oneof"` } +type Credentials_GcpSecretManager struct { + GcpSecretManager *Credentials_GCPSecretManager `protobuf:"bytes,3,opt,name=gcp_secret_manager,json=gcpSecretManager,proto3,oneof"` +} + func (*Credentials_AwsSecretManager) isCredentials_Backend() {} func (*Credentials_Vault_) isCredentials_Backend() {} +func (*Credentials_GcpSecretManager) isCredentials_Backend() {} + type Bootstrap_Observability struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -656,6 +670,61 @@ func (x *Credentials_Vault) GetMountPath() string { return "" } +type Credentials_GCPSecretManager struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` +} + +func (x *Credentials_GCPSecretManager) Reset() { + *x = Credentials_GCPSecretManager{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Credentials_GCPSecretManager) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Credentials_GCPSecretManager) ProtoMessage() {} + +func (x *Credentials_GCPSecretManager) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Credentials_GCPSecretManager.ProtoReflect.Descriptor instead. +func (*Credentials_GCPSecretManager) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{3, 2} +} + +func (x *Credentials_GCPSecretManager) GetProjectId() string { + if x != nil { + return x.ProjectId + } + return "" +} + +func (x *Credentials_GCPSecretManager) GetAuthKey() string { + if x != nil { + return x.AuthKey + } + return "" +} + type Credentials_AWSSecretManager_Creds struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -668,7 +737,7 @@ type Credentials_AWSSecretManager_Creds struct { func (x *Credentials_AWSSecretManager_Creds) Reset() { *x = Credentials_AWSSecretManager_Creds{} if protoimpl.UnsafeEnabled { - mi := &file_conf_proto_msgTypes[10] + mi := &file_conf_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -681,7 +750,7 @@ func (x *Credentials_AWSSecretManager_Creds) String() string { func (*Credentials_AWSSecretManager_Creds) ProtoMessage() {} func (x *Credentials_AWSSecretManager_Creds) ProtoReflect() protoreflect.Message { - mi := &file_conf_proto_msgTypes[10] + mi := &file_conf_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -763,8 +832,8 @@ var file_conf_proto_rawDesc = []byte{ 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0x9a, - 0x03, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4d, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0xb7, + 0x04, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4d, 0x0a, 0x12, 0x61, 0x77, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, 0x63, 0x72, @@ -772,29 +841,39 @@ var file_conf_proto_rawDesc = []byte{ 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x56, 0x61, 0x75, 0x6c, 0x74, - 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x1a, 0xac, 0x01, 0x0a, 0x10, 0x41, 0x57, - 0x53, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x39, - 0x0a, 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, - 0x64, 0x73, 0x52, 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, - 0x6e, 0x1a, 0x45, 0x0a, 0x05, 0x43, 0x72, 0x65, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x1a, 0x56, 0x0a, 0x05, 0x56, 0x61, 0x75, 0x6c, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, - 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x46, 0x5a, 0x44, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x62, 0x65, 0x64, 0x72, 0x6f, 0x63, 0x6b, 0x2f, - 0x61, 0x70, 0x70, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2d, 0x63, 0x61, 0x73, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, - 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x4d, 0x0a, 0x12, 0x67, 0x63, 0x70, + 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x73, 0x2e, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x67, 0x63, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x1a, 0xac, 0x01, 0x0a, 0x10, 0x41, 0x57, 0x53, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x39, 0x0a, + 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x64, + 0x73, 0x52, 0x05, 0x63, 0x72, 0x65, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, + 0x1a, 0x45, 0x0a, 0x05, 0x43, 0x72, 0x65, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x1a, 0x56, 0x0a, 0x05, 0x56, 0x61, 0x75, 0x6c, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x1a, + 0x4c, 0x0a, 0x10, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x42, 0x09, 0x0a, + 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, + 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, + 0x70, 0x70, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2d, 0x63, 0x61, 0x73, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, + 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -809,7 +888,7 @@ func file_conf_proto_rawDescGZIP() []byte { return file_conf_proto_rawDescData } -var file_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_conf_proto_goTypes = []interface{}{ (*Bootstrap)(nil), // 0: Bootstrap (*Server)(nil), // 1: Server @@ -821,8 +900,9 @@ var file_conf_proto_goTypes = []interface{}{ (*Server_GRPC)(nil), // 7: Server.GRPC (*Credentials_AWSSecretManager)(nil), // 8: Credentials.AWSSecretManager (*Credentials_Vault)(nil), // 9: Credentials.Vault - (*Credentials_AWSSecretManager_Creds)(nil), // 10: Credentials.AWSSecretManager.Creds - (*durationpb.Duration)(nil), // 11: google.protobuf.Duration + (*Credentials_GCPSecretManager)(nil), // 10: Credentials.GCPSecretManager + (*Credentials_AWSSecretManager_Creds)(nil), // 11: Credentials.AWSSecretManager.Creds + (*durationpb.Duration)(nil), // 12: google.protobuf.Duration } var file_conf_proto_depIdxs = []int32{ 1, // 0: Bootstrap.server:type_name -> Server @@ -834,15 +914,16 @@ var file_conf_proto_depIdxs = []int32{ 6, // 6: Server.http_metrics:type_name -> Server.HTTP 8, // 7: Credentials.aws_secret_manager:type_name -> Credentials.AWSSecretManager 9, // 8: Credentials.vault:type_name -> Credentials.Vault - 5, // 9: Bootstrap.Observability.sentry:type_name -> Bootstrap.Observability.Sentry - 11, // 10: Server.HTTP.timeout:type_name -> google.protobuf.Duration - 11, // 11: Server.GRPC.timeout:type_name -> google.protobuf.Duration - 10, // 12: Credentials.AWSSecretManager.creds:type_name -> Credentials.AWSSecretManager.Creds - 13, // [13:13] is the sub-list for method output_type - 13, // [13:13] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 10, // 9: Credentials.gcp_secret_manager:type_name -> Credentials.GCPSecretManager + 5, // 10: Bootstrap.Observability.sentry:type_name -> Bootstrap.Observability.Sentry + 12, // 11: Server.HTTP.timeout:type_name -> google.protobuf.Duration + 12, // 12: Server.GRPC.timeout:type_name -> google.protobuf.Duration + 11, // 13: Credentials.AWSSecretManager.creds:type_name -> Credentials.AWSSecretManager.Creds + 14, // [14:14] is the sub-list for method output_type + 14, // [14:14] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_conf_proto_init() } @@ -972,6 +1053,18 @@ func file_conf_proto_init() { } } file_conf_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Credentials_GCPSecretManager); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Credentials_AWSSecretManager_Creds); i { case 0: return &v.state @@ -987,6 +1080,7 @@ func file_conf_proto_init() { file_conf_proto_msgTypes[3].OneofWrappers = []interface{}{ (*Credentials_AwsSecretManager)(nil), (*Credentials_Vault_)(nil), + (*Credentials_GcpSecretManager)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -994,7 +1088,7 @@ func file_conf_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_conf_proto_rawDesc, NumEnums: 0, - NumMessages: 11, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, From 660d168a910377d344bffb029885d5232d1f2100 Mon Sep 17 00:00:00 2001 From: gr0 Date: Tue, 23 May 2023 10:13:13 +0200 Subject: [PATCH 04/23] Lint Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager.go | 31 ++++++++++++------- .../credentials/gcp/secretmanager_test.go | 25 ++++++++++++--- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index 92a15d98f..889f4fb2a 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -1,3 +1,18 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package gcp import ( @@ -54,7 +69,7 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { cli, err := secretmanager.NewRESTClient(context.TODO(), option.WithCredentialsJSON([]byte(opts.AuthKey))) if err != nil { - return nil, fmt.Errorf("error while connecting to the project: %v", err) + return nil, fmt.Errorf("error while connecting to the project: %w", err) } return &Manager{ @@ -133,19 +148,11 @@ func (m *Manager) DeleteCredentials(ctx context.Context, secretID string) error return fmt.Errorf("%w: path=%s", credentials.ErrNotFound, secretID) } -func (c *Manager) secretExists(ctx context.Context, secretID string) bool { +func (m *Manager) secretExists(ctx context.Context, secretID string) bool { accessRequest := secretmanagerpb.GetSecretRequest{ - Name: fmt.Sprintf("projects/%v/secrets/%v", c.projectID, secretID), + Name: fmt.Sprintf("projects/%v/secrets/%v", m.projectID, secretID), } - _, err := c.client.GetSecret(ctx, &accessRequest) + _, err := m.client.GetSecret(ctx, &accessRequest) return err == nil } - -// Close closes the manager -func (m *Manager) Close() error { - if m.client == nil { - return nil - } - return m.client.Close() -} diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go index 85c5e299b..801d9de58 100644 --- a/internal/credentials/gcp/secretmanager_test.go +++ b/internal/credentials/gcp/secretmanager_test.go @@ -1,3 +1,18 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package gcp import ( @@ -77,21 +92,21 @@ func TestReadCredentials(t *testing.T) { m := &Manager{} clientMock := gcpmocks.NewSecretsManagerInterface(t) m.client = clientMock - secretId := "some-secret-id" + secretID := "some-secret-id" validAPICreds := &credentials.APICreds{Host: "host", Key: "key"} payload, err := json.Marshal(validAPICreds) assert.NoError(t, err) clientMock.On("AccessSecretVersion", ctx, mock.Anything).Return(&secretmanagerpb.AccessSecretVersionResponse{ - Name: secretId, + Name: secretID, Payload: &secretmanagerpb.SecretPayload{ Data: payload, }, }, nil).Once() creds := &credentials.APICreds{} - err = m.ReadCredentials(ctx, secretId, creds) + err = m.ReadCredentials(ctx, secretID, creds) assert.NoError(t, err) assert.Equal(t, "host", creds.Host) assert.Equal(t, "key", creds.Key) @@ -102,11 +117,11 @@ func TestDeleteCredentials(t *testing.T) { clientMock := gcpmocks.NewSecretsManagerInterface(t) m.client = clientMock m.projectID = defaultProjectID - secretId := "some-secret-id" + secretID := "some-secret-id" clientMock.On("GetSecret", mock.Anything, mock.Anything).Return(&secretmanagerpb.Secret{}, nil).Once() clientMock.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - err := m.DeleteCredentials(context.Background(), secretId) + err := m.DeleteCredentials(context.Background(), secretID) assert.NoError(t, err) } From 6762a6617fd3e8f1118b4e8acdbd655180fbc593 Mon Sep 17 00:00:00 2001 From: gr0 Date: Tue, 23 May 2023 12:58:09 +0200 Subject: [PATCH 05/23] fix: downgrade GRPC to 1.54.0 to avoid problems with dependencies Signed-off-by: gr0 --- go.mod | 8 ++++---- go.sum | 9 +++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index f6edf8003..3e1aed6b7 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/chainloop-dev/chainloop go 1.20 require ( + cloud.google.com/go/secretmanager v1.10.0 code.cloudfoundry.org/bytefmt v0.0.0-20211005130812-5bb3c17173e5 cuelang.org/go v0.5.0 entgo.io/ent v0.11.9 @@ -28,6 +29,7 @@ require ( github.com/google/subcommands v1.0.1 github.com/google/uuid v1.3.0 github.com/google/wire v0.5.0 + github.com/googleapis/gax-go/v2 v2.8.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/hashicorp/vault/api v1.9.1 @@ -55,8 +57,9 @@ require ( golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874 golang.org/x/oauth2 v0.7.0 golang.org/x/term v0.7.0 + google.golang.org/api v0.119.0 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 - google.golang.org/grpc v1.55.0 + google.golang.org/grpc v1.54.0 google.golang.org/protobuf v1.30.0 sigs.k8s.io/yaml v1.3.0 ) @@ -66,7 +69,6 @@ require ( cloud.google.com/go/compute v1.19.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v0.13.0 // indirect - cloud.google.com/go/secretmanager v1.10.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.28 // indirect @@ -138,7 +140,6 @@ require ( github.com/google/s2a-go v0.1.2 // indirect github.com/google/trillian v1.5.1 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -229,7 +230,6 @@ require ( golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.7.0 // indirect - google.golang.org/api v0.119.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 8ca7789ea..d1debb626 100644 --- a/go.sum +++ b/go.sum @@ -50,12 +50,13 @@ cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= cloud.google.com/go/kms v1.10.1 h1:7hm1bRqGCA1GBRQUrp831TwJ9TWhP+tvLuP497CQS2g= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/secretmanager v1.10.1 h1:9QwQ3oMurvmPEmM80spGe2SFGDa+RRgkLIdTm3gMWO8= -cloud.google.com/go/secretmanager v1.10.1/go.mod h1:pxG0NLpcK6OMy54kfZgQmsKTPxJem708X1es7xv8n60= +cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= @@ -306,8 +307,6 @@ github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPO github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= @@ -1772,8 +1771,6 @@ google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 6366ab5c33955c130b0337e0b22892fab29c2c2a Mon Sep 17 00:00:00 2001 From: Miguel Martinez Trivino Date: Tue, 23 May 2023 11:52:35 +0200 Subject: [PATCH 06/23] chore(ci): check go mod tidiness (#126) Signed-off-by: Miguel Martinez Trivino Signed-off-by: gr0 --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7bc074785..1e77e50ac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,6 +28,11 @@ jobs: cache: true cache-dependency-path: go.sum + - name: Go Module tidy check + run: | + go mod tidy + git diff --exit-code -- go.mod go.sum + # Check that the generated ent code is up to date # see https://entgo.io/docs/ci/ - uses: ent/contrib/ci@master From fb779a9367728f68c34b70e37f5c830e48141ef9 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 14:03:32 +0200 Subject: [PATCH 07/23] fix: move marshaling to the beginning of the function to fail fast if there are issues with marshaling Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index 889f4fb2a..a76bc92a1 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -81,6 +81,12 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { // SaveCredentials saves credentials func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) (string, error) { + // store creds in key-value pair + c, err := json.Marshal(creds) + if err != nil { + return "", fmt.Errorf("marshaling credentials to be stored: %w", err) + } + secretID := strings.Join([]string{orgID, uuid.Generate().String()}, "-") // first create the secret itself @@ -100,12 +106,6 @@ func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) return "", fmt.Errorf("creating secret in GCP: %w", err) } - // store creds in key-value pair - c, err := json.Marshal(creds) - if err != nil { - return "", fmt.Errorf("marshaling credentials to be stored: %w", err) - } - // once the secret is created store it as the newest version addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ Parent: secret.Name, From 68d0faf12e405adc4d50885b8ec22078b3605014 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 14:20:38 +0200 Subject: [PATCH 08/23] feat: improve logging for GCP secret manager Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index a76bc92a1..6f818cb60 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -71,6 +71,7 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { if err != nil { return nil, fmt.Errorf("error while connecting to the project: %w", err) } + logger.Infow("msg", "created GCP connection", "projectID", opts.ProjectID) return &Manager{ projectID: opts.ProjectID, @@ -105,6 +106,7 @@ func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) if err != nil { return "", fmt.Errorf("creating secret in GCP: %w", err) } + m.logger.Infow("msg", "created new secrect", "secretID", secretID) // once the secret is created store it as the newest version addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ @@ -113,10 +115,12 @@ func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) Data: c, }, } - _, err = m.client.AddSecretVersion(ctx, addSecretVersionReq) + + v, err := m.client.AddSecretVersion(ctx, addSecretVersionReq) if err != nil { return "", fmt.Errorf("creating secret version in GCP: %w", err) } + m.logger.Infow("msg", "added new secret version", "secretID", secretID, "versionID", v.Name) return secretID, nil } @@ -131,6 +135,7 @@ func (m *Manager) ReadCredentials(ctx context.Context, secretID string, creds an if err != nil { return fmt.Errorf("%w: path=%s", credentials.ErrNotFound, secretID) } + m.logger.Infow("msg", "accessed secret", "secretID", secretID) return json.Unmarshal(result.Payload.Data, creds) } @@ -141,6 +146,7 @@ func (m *Manager) DeleteCredentials(ctx context.Context, secretID string) error deleteRequest := secretmanagerpb.DeleteSecretRequest{ Name: fmt.Sprintf("projects/%v/secrets/%v", m.projectID, secretID), } + m.logger.Infow("msg", "deleting secret", "secretID", secretID) return m.client.DeleteSecret(ctx, &deleteRequest) } From 7d6610f51c0b281056db70cdbe3289677a92b1fe Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 14:25:38 +0200 Subject: [PATCH 09/23] fix(docs): add information about support for GCP Secres Manager to CAS README.md file Signed-off-by: gr0 --- app/artifact-cas/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/artifact-cas/README.md b/app/artifact-cas/README.md index 0a152c8d4..8ae578ada 100644 --- a/app/artifact-cas/README.md +++ b/app/artifact-cas/README.md @@ -20,7 +20,7 @@ Its structure contains the following top to down layers. ## System Dependencies -The CAS proxy **has only one running dependency**. A secret storage backend to retrieve the OCI repository credentials. Currently, we support both [Hashicorp Vault](https://www.vaultproject.io/) and [AWS Secret Manager](https://aws.amazon.com/secrets-manager/). +The CAS proxy **has only one running dependency**. A secret storage backend to retrieve the OCI repository credentials. Currently, we support [Hashicorp Vault](https://www.vaultproject.io/), [AWS Secret Manager](https://aws.amazon.com/secrets-manager/) AND [GCP Secret Manager](https://cloud.google.com/secret-manager). This secret backend is used to download OCI repository credentials (repository path + key pair) during upload/downloads. This makes the Artifact CAS multi-tenant by default since the destination OCI backend gets selected at runtime. From ce485622605582c4c42742086a74dd110cb6d5b7 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 14:42:54 +0200 Subject: [PATCH 10/23] fix: remove the check when initializing credentials manager Signed-off-by: gr0 --- app/artifact-cas/cmd/main.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/artifact-cas/cmd/main.go b/app/artifact-cas/cmd/main.go index f571bb513..bebb455fb 100644 --- a/app/artifact-cas/cmd/main.go +++ b/app/artifact-cas/cmd/main.go @@ -126,13 +126,6 @@ func main() { } func newCredentialsReader(conf *conf.Credentials, l log.Logger) (credentials.Reader, error) { - awsc, vaultc, gcpc := conf.GetAwsSecretManager(), conf.GetVault(), conf.GetGcpSecretManager() - if awsc == nil && vaultc == nil && gcpc == nil { - return nil, errors.New("no credentials manager configuration found") - } else if awsc != nil && vaultc != nil && gcpc != nil { - return nil, errors.New("only one credentials manager can be configured") - } - if c := conf.GetAwsSecretManager(); c != nil { return newAWSCredentialsManager(c, l) } From 15bb5afc91aeaefd86dd6e87b1409814a190fdf8 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 14:45:32 +0200 Subject: [PATCH 11/23] fix: initialize logger in tests Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go index 801d9de58..ad7a1d0cf 100644 --- a/internal/credentials/gcp/secretmanager_test.go +++ b/internal/credentials/gcp/secretmanager_test.go @@ -18,11 +18,14 @@ package gcp import ( "context" "encoding/json" + "io" "testing" "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" "github.com/chainloop-dev/chainloop/internal/credentials" gcpmocks "github.com/chainloop-dev/chainloop/internal/credentials/gcp/mocks" + "github.com/chainloop-dev/chainloop/internal/servicelogger" + "github.com/go-kratos/kratos/v2/log" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -77,6 +80,7 @@ func TestCreateCredentials(t *testing.T) { ctx := context.Background() m := &Manager{} + m.logger = servicelogger.ScopedHelper(log.NewStdLogger(io.Discard), "credentials/gcp-secrets-manager") clientMock := gcpmocks.NewSecretsManagerInterface(t) m.client = clientMock @@ -90,6 +94,7 @@ func TestCreateCredentials(t *testing.T) { func TestReadCredentials(t *testing.T) { ctx := context.Background() m := &Manager{} + m.logger = servicelogger.ScopedHelper(log.NewStdLogger(io.Discard), "credentials/gcp-secrets-manager") clientMock := gcpmocks.NewSecretsManagerInterface(t) m.client = clientMock secretID := "some-secret-id" @@ -114,6 +119,7 @@ func TestReadCredentials(t *testing.T) { func TestDeleteCredentials(t *testing.T) { m := &Manager{} + m.logger = servicelogger.ScopedHelper(log.NewStdLogger(io.Discard), "credentials/gcp-secrets-manager") clientMock := gcpmocks.NewSecretsManagerInterface(t) m.client = clientMock m.projectID = defaultProjectID From d61212d0b7ba7b00dc507cf074a93a93d3931454 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 14:50:21 +0200 Subject: [PATCH 12/23] fix: remove the unused Close() function from GCP secrets manager and regenerate the mock Signed-off-by: gr0 --- .../gcp/mocks/SecretsManagerInterface.go | 16 +--------------- internal/credentials/gcp/secretmanager.go | 1 - 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/internal/credentials/gcp/mocks/SecretsManagerInterface.go b/internal/credentials/gcp/mocks/SecretsManagerInterface.go index 4102b7c03..9ac49cf55 100644 --- a/internal/credentials/gcp/mocks/SecretsManagerInterface.go +++ b/internal/credentials/gcp/mocks/SecretsManagerInterface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. +// Code generated by mockery v2.20.0. DO NOT EDIT. package mocks @@ -83,20 +83,6 @@ func (_m *SecretsManagerInterface) AddSecretVersion(ctx context.Context, req *se return r0, r1 } -// Close provides a mock function with given fields: -func (_m *SecretsManagerInterface) Close() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - // CreateSecret provides a mock function with given fields: ctx, req, opts func (_m *SecretsManagerInterface) CreateSecret(ctx context.Context, req *secretmanagerpb.CreateSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) { _va := make([]interface{}, len(opts)) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index 6f818cb60..b5ae3aae8 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -40,7 +40,6 @@ type SecretsManagerInterface interface { AccessSecretVersion(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) DeleteSecret(ctx context.Context, req *secretmanagerpb.DeleteSecretRequest, opts ...gax.CallOption) error GetSecret(ctx context.Context, req *secretmanagerpb.GetSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) - Close() error } type Manager struct { From 3613713f3f049d2a83588ed40970b474cb7e9a70 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 16:29:32 +0200 Subject: [PATCH 13/23] fix: provide an example configuration and use key instead of passing the full credentials in configuration Signed-off-by: gr0 --- app/artifact-cas/configs/samples/config.yaml | 4 ++++ .../credentials/gcp/_fixtures/gcp_key.json | 13 +++++++++++++ internal/credentials/gcp/secretmanager.go | 9 ++++++++- internal/credentials/gcp/secretmanager_test.go | 18 +++--------------- 4 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 internal/credentials/gcp/_fixtures/gcp_key.json diff --git a/app/artifact-cas/configs/samples/config.yaml b/app/artifact-cas/configs/samples/config.yaml index 961bff885..997fd8d8d 100644 --- a/app/artifact-cas/configs/samples/config.yaml +++ b/app/artifact-cas/configs/samples/config.yaml @@ -22,3 +22,7 @@ observability: sentry: dsn: "http://sentryDomain" environment: development # production + +## gcp_secret_manager: +## project_id: 522312304548 +## auth_key: "./configs/gcp_auth_key.json" \ No newline at end of file diff --git a/internal/credentials/gcp/_fixtures/gcp_key.json b/internal/credentials/gcp/_fixtures/gcp_key.json new file mode 100644 index 000000000..c1f85ed62 --- /dev/null +++ b/internal/credentials/gcp/_fixtures/gcp_key.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "chainloop-dev", + "private_key_id": "3739437f557d4d82283c04573865c508e6bc6038", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDTJ2KDLgiBjoNm\nfEkbZvBJvLSCXKBol5NYJXsqmyZNPoWWcvRlMsBUn5u1+ibucXPmjDtaekr1j3n5\nnnLY1HgMmS6BX7wE7f2aiHouIafTSHT04kw6khxkuYc7qpFTUKrwkH5rBsDsu3S9\nkZs1pv2PAc9Qr2FA3g9gGv+jtAhIk5vaqskGfsndtIpnx0IxCvfelwGERZ/XUrlD\nHkfAlA6tkLO+WbP76qez3d/qPh1ftIgVw+hOUSLLc8S9xoT41hkCyXqiA+ELzam7\nMrQr1jY6NX4ttVQt1+mad3v1nYnzJ4G91Ty7S80Mp8cVDtdWJM4aBeI4Q3/PyqBM\n5Ir8OP+BAgMBAAECggEAMJvdetNrE+Ap8brk3ZEJ+f+eEnCeYNWcDuu5+enznE6r\nVCIsjutrCVAg+XiX48ZsZwObWk3S2croyoUmbTIkXMoawZ+3We8rtZp7fgkzaFlC\ny2kZIVangKyRLDQs9mAYqf6pi5vnZ9gTnNxbPbOupXBGOI3XNqaoJXixpw735TTi\nk6qP85U6zYHCI+2QFD7cLt7CE2r/2yV61rSTByDY+uowq1R0kjNqX0J0XW529Rdh\nSlyzvjuBqzYuOM/0JpRwPXFbw6WK5MsRNkkDbjS2vyhM+1l9FDQG03ealx0FvnSb\nA8i93Dt7io+6yB7TDAhJAdHMNEXRVXD79fiKox8oUQKBgQD6LE2kjQ2N4+MtFwYL\nsoA9BRela0XEruyCxFCZl7YTka9A28G62hu0B+NW/VlgSjBzv0dxy0avlL+5xmrl\n4ISI0QJKuK/2ZSr00YU2OBoMN3UokA2mxVvtoKLgybZK5Lt7Nocq2V7b2o2epdcp\nAYK/O4wckvHOKnduuwFFluf+/QKBgQDYEmxaPord5DDVeROK7nuE4M/S+Wc9LlDD\n59R0hgZhZcZFzwKadH6zAuSZ7fLMdv4o1wD7smDE66wYJpPa2R5si9GEbiISWdaC\nu1ENxXF0JbApTPrdjWNynAooLrWq4adfWciEzxXBMRixXuruRPc4l5pEDtx74tAB\nWMxNfs5j1QKBgQCYc2EJMo+c9M9ejdY4UJmHFdBYFKvadIJaGcnIH0RsXm3+xywi\ncoFJTzlBrHfHjs5B6sFd3fMAUlQXoItJ9Gyvdza/VBaevv3TXM6hwMRWx4DUrBw1\nkbU4dJhtBV7Z+tMo/YyXFwmQTnnYwNUB/xKu+FmknANQkF5hkwHuZ0yO/QKBgQDR\nvDhe9PyY3IqmfIuCvXE6j3pMAPm8gnu1XhB1Ny90VXU7h/Cv+sqNew5peHbJD+wv\nulvi9chG/bikDLZSpZSJqsKqeLkr9PZrGeZYpsI1CuxPesC8VCUnN94IGScQg0+T\nF7SzbcxhJgYhDdCfjmQnE8mTrJVKz+Q2mnpd8uvmLQKBgQDdtpUdf5gmY8l8E8x/\nV3qRQt3+bVPn6wzVj/MtEmaqSxESQmXwoBxxabrhvZhxuueeEYm0FO7l9yCs/rCM\nf8LnTEHtOKEJ3DjirfreVB6KRBNTIrJLdWQr0A7VO4dqDnAHQlVrXGor0df7VO+u\nwoPesVoQ3NZgLdVmdMdSDF0xlA==\n-----END PRIVATE KEY-----\n", + "client_email": "chainloop-service-account@chainloop-dev.iam.gserviceaccount.com", + "client_id": "133229671234657229293", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/russell-service-account%40archipelo-dev.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" + } \ No newline at end of file diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index b5ae3aae8..14e222181 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "io" + "os" "strings" secretmanager "cloud.google.com/go/secretmanager/apiv1" @@ -66,7 +67,13 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { logger := servicelogger.ScopedHelper(l, "credentials/gcp-secrets-manager") logger.Infow("msg", "configuring gcp secrets-manager", "projectID", opts.ProjectID) - cli, err := secretmanager.NewRESTClient(context.TODO(), option.WithCredentialsJSON([]byte(opts.AuthKey))) + // read credentials file + authKey, err := os.ReadFile(opts.AuthKey) + if err != nil { + return nil, fmt.Errorf("error while reading auth key file: %w", err) + } + + cli, err := secretmanager.NewClient(context.TODO(), option.WithCredentialsJSON(authKey)) if err != nil { return nil, fmt.Errorf("error while connecting to the project: %w", err) } diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go index ad7a1d0cf..daf2408cf 100644 --- a/internal/credentials/gcp/secretmanager_test.go +++ b/internal/credentials/gcp/secretmanager_test.go @@ -32,19 +32,7 @@ import ( const defaultOrgID = "test-org" const defaultProjectID = "1234-5678-9012" -const defaultAccessKey string = `{ - "type": "service_account", - "project_id": "chainloop-test-dev", - "private_key_id": "12345123451234512345", - "private_key": "-----BEGIN PRIVATE KEY-----\nAAABBB\n-----END PRIVATE KEY-----\n", - "client_email": "chainloop-dev@chainloop-dev.iam.gserviceaccount.com", - "client_id": "5678567856781234", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/chainloop-dev%40chainloop-dev.iam.gserviceaccount.com", - "universe_domain": "googleapis.com" -}` +const defaultAuthKey string = "./_fixtures/gcp_key.json" func TestNewManager(t *testing.T) { assert := assert.New(t) @@ -55,9 +43,9 @@ func TestNewManager(t *testing.T) { authKey string expectedError bool }{ - {name: "missing projectID", projectID: "", authKey: defaultAccessKey, expectedError: true}, + {name: "missing projectID", projectID: "", authKey: defaultAuthKey, expectedError: true}, {name: "missing authKey", projectID: defaultProjectID, authKey: "", expectedError: true}, - {name: "valid manager", projectID: defaultProjectID, authKey: defaultAccessKey}, + {name: "valid manager", projectID: defaultProjectID, authKey: defaultAuthKey}, } for _, tc := range testCases { From 4739865eca1f6da4ed439fae9d0e11831c6efcc6 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 16:39:49 +0200 Subject: [PATCH 14/23] fix: add support for secret prefix in GCP and use the gRPC client Signed-off-by: gr0 --- app/artifact-cas/cmd/main.go | 7 ++-- app/artifact-cas/configs/samples/config.yaml | 3 +- app/artifact-cas/internal/conf/conf.pb.go | 32 ++++++++++++------- app/artifact-cas/internal/conf/conf.proto | 1 + app/controlplane/cmd/main.go | 7 ++-- app/controlplane/internal/conf/conf.pb.go | 32 ++++++++++++------- .../internal/conf/conf.pb.validate.go | 2 ++ app/controlplane/internal/conf/conf.proto | 1 + internal/credentials/gcp/secretmanager.go | 20 ++++++------ 9 files changed, 67 insertions(+), 38 deletions(-) diff --git a/app/artifact-cas/cmd/main.go b/app/artifact-cas/cmd/main.go index bebb455fb..a71e93e1a 100644 --- a/app/artifact-cas/cmd/main.go +++ b/app/artifact-cas/cmd/main.go @@ -184,9 +184,10 @@ func newGCPCredentialsManager(conf *conf.Credentials_GCPSecretManager, l log.Log } opts := &gcp.NewManagerOpts{ - ProjectID: conf.ProjectId, - AuthKey: conf.AuthKey, - Logger: l, + ProjectID: conf.ProjectId, + AuthKey: conf.AuthKey, + SecretPrefix: conf.SecretPrefix, + Logger: l, } m, err := gcp.NewManager(opts) diff --git a/app/artifact-cas/configs/samples/config.yaml b/app/artifact-cas/configs/samples/config.yaml index 997fd8d8d..142f4065c 100644 --- a/app/artifact-cas/configs/samples/config.yaml +++ b/app/artifact-cas/configs/samples/config.yaml @@ -25,4 +25,5 @@ observability: ## gcp_secret_manager: ## project_id: 522312304548 -## auth_key: "./configs/gcp_auth_key.json" \ No newline at end of file +## auth_key: "./configs/gcp_auth_key.json" +## secret_prefix: "pre-" \ No newline at end of file diff --git a/app/artifact-cas/internal/conf/conf.pb.go b/app/artifact-cas/internal/conf/conf.pb.go index 22db85538..607dc37e9 100644 --- a/app/artifact-cas/internal/conf/conf.pb.go +++ b/app/artifact-cas/internal/conf/conf.pb.go @@ -675,8 +675,9 @@ type Credentials_GCPSecretManager struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` - AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` + ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` + SecretPrefix string `protobuf:"bytes,3,opt,name=secret_prefix,json=secretPrefix,proto3" json:"secret_prefix,omitempty"` } func (x *Credentials_GCPSecretManager) Reset() { @@ -725,6 +726,13 @@ func (x *Credentials_GCPSecretManager) GetAuthKey() string { return "" } +func (x *Credentials_GCPSecretManager) GetSecretPrefix() string { + if x != nil { + return x.SecretPrefix + } + return "" +} + type Credentials_AWSSecretManager_Creds struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -832,7 +840,7 @@ var file_conf_proto_rawDesc = []byte{ 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0xb7, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0xdc, 0x04, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4d, 0x0a, 0x12, 0x61, 0x77, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, @@ -863,17 +871,19 @@ var file_conf_proto_rawDesc = []byte{ 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x1a, - 0x4c, 0x0a, 0x10, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, + 0x71, 0x0a, 0x10, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x42, 0x09, 0x0a, - 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, - 0x70, 0x70, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2d, 0x63, 0x61, 0x73, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, - 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, + 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, + 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x2d, 0x63, 0x61, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, + 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/artifact-cas/internal/conf/conf.proto b/app/artifact-cas/internal/conf/conf.proto index 6b2cbb3c7..d8159ae2e 100644 --- a/app/artifact-cas/internal/conf/conf.proto +++ b/app/artifact-cas/internal/conf/conf.proto @@ -93,5 +93,6 @@ message Credentials { message GCPSecretManager { string project_id = 1; string auth_key = 2; + string secret_prefix = 3; } } \ No newline at end of file diff --git a/app/controlplane/cmd/main.go b/app/controlplane/cmd/main.go index 36e8e44bb..a3187a83e 100644 --- a/app/controlplane/cmd/main.go +++ b/app/controlplane/cmd/main.go @@ -223,9 +223,10 @@ func newGCPCredentialsManager(conf *conf.Credentials_GCPSecretManager, l log.Log } opts := &gcp.NewManagerOpts{ - ProjectID: conf.ProjectId, - AuthKey: conf.AuthKey, - Logger: l, + ProjectID: conf.ProjectId, + AuthKey: conf.AuthKey, + SecretPrefix: conf.SecretPrefix, + Logger: l, } m, err := gcp.NewManager(opts) diff --git a/app/controlplane/internal/conf/conf.pb.go b/app/controlplane/internal/conf/conf.pb.go index a6cc65a0c..88af3338f 100644 --- a/app/controlplane/internal/conf/conf.pb.go +++ b/app/controlplane/internal/conf/conf.pb.go @@ -968,8 +968,9 @@ type Credentials_GCPSecretManager struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` - AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` + ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` + SecretPrefix string `protobuf:"bytes,3,opt,name=secret_prefix,json=secretPrefix,proto3" json:"secret_prefix,omitempty"` } func (x *Credentials_GCPSecretManager) Reset() { @@ -1018,6 +1019,13 @@ func (x *Credentials_GCPSecretManager) GetAuthKey() string { return "" } +func (x *Credentials_GCPSecretManager) GetSecretPrefix() string { + if x != nil { + return x.SecretPrefix + } + return "" +} + type Credentials_AWSSecretManager_Creds struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1165,7 +1173,7 @@ var file_conf_proto_rawDesc = []byte{ 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, - 0x22, 0x81, 0x05, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x22, 0xa6, 0x05, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4d, 0x0a, 0x12, 0x61, 0x77, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, @@ -1199,18 +1207,20 @@ var file_conf_proto_rawDesc = []byte{ 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0x4c, 0x0a, 0x10, 0x47, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0x71, 0x0a, 0x10, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x63, - 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, - 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x09, + 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, + 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, + 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/controlplane/internal/conf/conf.pb.validate.go b/app/controlplane/internal/conf/conf.pb.validate.go index e7bcbd277..de27acf7b 100644 --- a/app/controlplane/internal/conf/conf.pb.validate.go +++ b/app/controlplane/internal/conf/conf.pb.validate.go @@ -2118,6 +2118,8 @@ func (m *Credentials_GCPSecretManager) validate(all bool) error { // no validation rules for AuthKey + // no validation rules for SecretPrefix + if len(errors) > 0 { return Credentials_GCPSecretManagerMultiError(errors) } diff --git a/app/controlplane/internal/conf/conf.proto b/app/controlplane/internal/conf/conf.proto index 26336144f..2fd2fee2d 100644 --- a/app/controlplane/internal/conf/conf.proto +++ b/app/controlplane/internal/conf/conf.proto @@ -124,5 +124,6 @@ message Credentials { message GCPSecretManager { string project_id = 1; string auth_key = 2; + string secret_prefix = 3; } } \ No newline at end of file diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index 14e222181..d61fed44b 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -44,14 +44,15 @@ type SecretsManagerInterface interface { } type Manager struct { - projectID string - client SecretsManagerInterface - logger *log.Helper + projectID string + secretPrefix string + client SecretsManagerInterface + logger *log.Helper } type NewManagerOpts struct { - ProjectID, AuthKey string - Logger log.Logger + ProjectID, AuthKey, SecretPrefix string + Logger log.Logger } func NewManager(opts *NewManagerOpts) (*Manager, error) { @@ -80,9 +81,10 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { logger.Infow("msg", "created GCP connection", "projectID", opts.ProjectID) return &Manager{ - projectID: opts.ProjectID, - client: cli, - logger: logger, + projectID: opts.ProjectID, + secretPrefix: opts.SecretPrefix, + client: cli, + logger: logger, }, nil } @@ -94,7 +96,7 @@ func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) return "", fmt.Errorf("marshaling credentials to be stored: %w", err) } - secretID := strings.Join([]string{orgID, uuid.Generate().String()}, "-") + secretID := strings.Join([]string{m.secretPrefix, orgID, uuid.Generate().String()}, "-") // first create the secret itself createSecretReq := &secretmanagerpb.CreateSecretRequest{ From 93f62a1d21bc21f399c02bfb7ad47424e6f2f3fe Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 16:40:32 +0200 Subject: [PATCH 15/23] fix: logging adjustment Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index d61fed44b..70dd42551 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -76,7 +76,7 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { cli, err := secretmanager.NewClient(context.TODO(), option.WithCredentialsJSON(authKey)) if err != nil { - return nil, fmt.Errorf("error while connecting to the project: %w", err) + return nil, fmt.Errorf("error while creating the client: %w", err) } logger.Infow("msg", "created GCP connection", "projectID", opts.ProjectID) From be5c44093ac059465a2c5b27f7c0dbe6f8e11a43 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 17:02:10 +0200 Subject: [PATCH 16/23] fix: rename the configuration related the GCP key' Signed-off-by: gr0 --- app/artifact-cas/cmd/main.go | 8 ++-- app/artifact-cas/internal/conf/conf.pb.go | 42 ++++++++++-------- app/artifact-cas/internal/conf/conf.proto | 4 +- app/controlplane/cmd/main.go | 8 ++-- app/controlplane/internal/conf/conf.pb.go | 44 ++++++++++--------- .../internal/conf/conf.pb.validate.go | 2 +- app/controlplane/internal/conf/conf.proto | 4 +- internal/credentials/gcp/secretmanager.go | 12 ++--- .../credentials/gcp/secretmanager_test.go | 18 ++++---- 9 files changed, 77 insertions(+), 65 deletions(-) diff --git a/app/artifact-cas/cmd/main.go b/app/artifact-cas/cmd/main.go index a71e93e1a..02f327412 100644 --- a/app/artifact-cas/cmd/main.go +++ b/app/artifact-cas/cmd/main.go @@ -184,10 +184,10 @@ func newGCPCredentialsManager(conf *conf.Credentials_GCPSecretManager, l log.Log } opts := &gcp.NewManagerOpts{ - ProjectID: conf.ProjectId, - AuthKey: conf.AuthKey, - SecretPrefix: conf.SecretPrefix, - Logger: l, + ProjectID: conf.ProjectId, + ServiceAccountKey: conf.ServiceAccountKey, + SecretPrefix: conf.SecretPrefix, + Logger: l, } m, err := gcp.NewManager(opts) diff --git a/app/artifact-cas/internal/conf/conf.pb.go b/app/artifact-cas/internal/conf/conf.pb.go index 607dc37e9..f568aedab 100644 --- a/app/artifact-cas/internal/conf/conf.pb.go +++ b/app/artifact-cas/internal/conf/conf.pb.go @@ -675,9 +675,11 @@ type Credentials_GCPSecretManager struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` - AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` - SecretPrefix string `protobuf:"bytes,3,opt,name=secret_prefix,json=secretPrefix,proto3" json:"secret_prefix,omitempty"` + // project number + ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + // service account key + ServiceAccountKey string `protobuf:"bytes,2,opt,name=service_account_key,json=serviceAccountKey,proto3" json:"service_account_key,omitempty"` + SecretPrefix string `protobuf:"bytes,3,opt,name=secret_prefix,json=secretPrefix,proto3" json:"secret_prefix,omitempty"` } func (x *Credentials_GCPSecretManager) Reset() { @@ -719,9 +721,9 @@ func (x *Credentials_GCPSecretManager) GetProjectId() string { return "" } -func (x *Credentials_GCPSecretManager) GetAuthKey() string { +func (x *Credentials_GCPSecretManager) GetServiceAccountKey() string { if x != nil { - return x.AuthKey + return x.ServiceAccountKey } return "" } @@ -840,7 +842,7 @@ var file_conf_proto_rawDesc = []byte{ 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0xdc, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0xf2, 0x04, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4d, 0x0a, 0x12, 0x61, 0x77, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, @@ -871,19 +873,21 @@ var file_conf_proto_rawDesc = []byte{ 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x1a, - 0x71, 0x0a, 0x10, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, - 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, - 0x69, 0x78, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, - 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x2d, 0x63, 0x61, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, - 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x86, 0x01, 0x0a, 0x10, 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, + 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x61, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2d, 0x63, 0x61, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/artifact-cas/internal/conf/conf.proto b/app/artifact-cas/internal/conf/conf.proto index d8159ae2e..1166538f4 100644 --- a/app/artifact-cas/internal/conf/conf.proto +++ b/app/artifact-cas/internal/conf/conf.proto @@ -91,8 +91,10 @@ message Credentials { } message GCPSecretManager { + // project number string project_id = 1; - string auth_key = 2; + // service account key + string service_account_key = 2; string secret_prefix = 3; } } \ No newline at end of file diff --git a/app/controlplane/cmd/main.go b/app/controlplane/cmd/main.go index a3187a83e..3d3c71a2c 100644 --- a/app/controlplane/cmd/main.go +++ b/app/controlplane/cmd/main.go @@ -223,10 +223,10 @@ func newGCPCredentialsManager(conf *conf.Credentials_GCPSecretManager, l log.Log } opts := &gcp.NewManagerOpts{ - ProjectID: conf.ProjectId, - AuthKey: conf.AuthKey, - SecretPrefix: conf.SecretPrefix, - Logger: l, + ProjectID: conf.ProjectId, + ServiceAccountKey: conf.ServiceAccountKey, + SecretPrefix: conf.SecretPrefix, + Logger: l, } m, err := gcp.NewManager(opts) diff --git a/app/controlplane/internal/conf/conf.pb.go b/app/controlplane/internal/conf/conf.pb.go index 88af3338f..c7e8ef4b9 100644 --- a/app/controlplane/internal/conf/conf.pb.go +++ b/app/controlplane/internal/conf/conf.pb.go @@ -968,9 +968,11 @@ type Credentials_GCPSecretManager struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` - AuthKey string `protobuf:"bytes,2,opt,name=auth_key,json=authKey,proto3" json:"auth_key,omitempty"` - SecretPrefix string `protobuf:"bytes,3,opt,name=secret_prefix,json=secretPrefix,proto3" json:"secret_prefix,omitempty"` + // project number + ProjectId string `protobuf:"bytes,1,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + // service account key + ServiceAccountKey string `protobuf:"bytes,2,opt,name=service_account_key,json=serviceAccountKey,proto3" json:"service_account_key,omitempty"` + SecretPrefix string `protobuf:"bytes,3,opt,name=secret_prefix,json=secretPrefix,proto3" json:"secret_prefix,omitempty"` } func (x *Credentials_GCPSecretManager) Reset() { @@ -1012,9 +1014,9 @@ func (x *Credentials_GCPSecretManager) GetProjectId() string { return "" } -func (x *Credentials_GCPSecretManager) GetAuthKey() string { +func (x *Credentials_GCPSecretManager) GetServiceAccountKey() string { if x != nil { - return x.AuthKey + return x.ServiceAccountKey } return "" } @@ -1173,7 +1175,7 @@ var file_conf_proto_rawDesc = []byte{ 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, - 0x22, 0xa6, 0x05, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x22, 0xbc, 0x05, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4d, 0x0a, 0x12, 0x61, 0x77, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, @@ -1207,20 +1209,22 @@ var file_conf_proto_rawDesc = []byte{ 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0x71, 0x0a, 0x10, 0x47, - 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, - 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x19, - 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x09, - 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, - 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, - 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0x86, 0x01, 0x0a, 0x10, + 0x47, 0x43, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, + 0x2e, 0x0a, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, + 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x42, 0x09, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x42, + 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/app/controlplane/internal/conf/conf.pb.validate.go b/app/controlplane/internal/conf/conf.pb.validate.go index de27acf7b..375d376fd 100644 --- a/app/controlplane/internal/conf/conf.pb.validate.go +++ b/app/controlplane/internal/conf/conf.pb.validate.go @@ -2116,7 +2116,7 @@ func (m *Credentials_GCPSecretManager) validate(all bool) error { // no validation rules for ProjectId - // no validation rules for AuthKey + // no validation rules for ServiceAccountKey // no validation rules for SecretPrefix diff --git a/app/controlplane/internal/conf/conf.proto b/app/controlplane/internal/conf/conf.proto index 2fd2fee2d..6fffa2048 100644 --- a/app/controlplane/internal/conf/conf.proto +++ b/app/controlplane/internal/conf/conf.proto @@ -122,8 +122,10 @@ message Credentials { } message GCPSecretManager { + // project number string project_id = 1; - string auth_key = 2; + // service account key + string service_account_key = 2; string secret_prefix = 3; } } \ No newline at end of file diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index 70dd42551..db6e40f48 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -51,13 +51,13 @@ type Manager struct { } type NewManagerOpts struct { - ProjectID, AuthKey, SecretPrefix string - Logger log.Logger + ProjectID, ServiceAccountKey, SecretPrefix string + Logger log.Logger } func NewManager(opts *NewManagerOpts) (*Manager, error) { - if opts.ProjectID == "" || opts.AuthKey == "" { - return nil, errors.New("projectID and authKey are required") + if opts.ProjectID == "" || opts.ServiceAccountKey == "" { + return nil, errors.New("projectID and serviceAccountKey are required") } l := opts.Logger @@ -69,12 +69,12 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { logger.Infow("msg", "configuring gcp secrets-manager", "projectID", opts.ProjectID) // read credentials file - authKey, err := os.ReadFile(opts.AuthKey) + serviceAccountKey, err := os.ReadFile(opts.ServiceAccountKey) if err != nil { return nil, fmt.Errorf("error while reading auth key file: %w", err) } - cli, err := secretmanager.NewClient(context.TODO(), option.WithCredentialsJSON(authKey)) + cli, err := secretmanager.NewClient(context.TODO(), option.WithCredentialsJSON(serviceAccountKey)) if err != nil { return nil, fmt.Errorf("error while creating the client: %w", err) } diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go index daf2408cf..3ce7ad35a 100644 --- a/internal/credentials/gcp/secretmanager_test.go +++ b/internal/credentials/gcp/secretmanager_test.go @@ -32,25 +32,25 @@ import ( const defaultOrgID = "test-org" const defaultProjectID = "1234-5678-9012" -const defaultAuthKey string = "./_fixtures/gcp_key.json" +const defaultServiceAccountKey string = "./_fixtures/gcp_key.json" func TestNewManager(t *testing.T) { assert := assert.New(t) testCases := []struct { - name string - projectID string - authKey string - expectedError bool + name string + projectID string + serviceAccountKey string + expectedError bool }{ - {name: "missing projectID", projectID: "", authKey: defaultAuthKey, expectedError: true}, - {name: "missing authKey", projectID: defaultProjectID, authKey: "", expectedError: true}, - {name: "valid manager", projectID: defaultProjectID, authKey: defaultAuthKey}, + {name: "missing projectID", projectID: "", serviceAccountKey: defaultServiceAccountKey, expectedError: true}, + {name: "missing authKey", projectID: defaultProjectID, serviceAccountKey: "", expectedError: true}, + {name: "valid manager", projectID: defaultProjectID, serviceAccountKey: defaultServiceAccountKey}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - opts := &NewManagerOpts{ProjectID: tc.projectID, AuthKey: tc.authKey} + opts := &NewManagerOpts{ProjectID: tc.projectID, ServiceAccountKey: tc.serviceAccountKey} _, err := NewManager(opts) if tc.expectedError { assert.Error(err) From 3088ab72b837f3081a8d9c597962e2c24ee8ede7 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 17:23:04 +0200 Subject: [PATCH 17/23] fix: avoid checking for existence of the secret before deletion Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager.go | 19 +++---------------- .../credentials/gcp/secretmanager_test.go | 1 - 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index db6e40f48..f75ae72d7 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -150,23 +150,10 @@ func (m *Manager) ReadCredentials(ctx context.Context, secretID string, creds an // DeleteCredentials deletes credentials and versions func (m *Manager) DeleteCredentials(ctx context.Context, secretID string) error { - if m.secretExists(ctx, secretID) { - deleteRequest := secretmanagerpb.DeleteSecretRequest{ - Name: fmt.Sprintf("projects/%v/secrets/%v", m.projectID, secretID), - } - m.logger.Infow("msg", "deleting secret", "secretID", secretID) - - return m.client.DeleteSecret(ctx, &deleteRequest) - } - - return fmt.Errorf("%w: path=%s", credentials.ErrNotFound, secretID) -} - -func (m *Manager) secretExists(ctx context.Context, secretID string) bool { - accessRequest := secretmanagerpb.GetSecretRequest{ + deleteRequest := secretmanagerpb.DeleteSecretRequest{ Name: fmt.Sprintf("projects/%v/secrets/%v", m.projectID, secretID), } + m.logger.Infow("msg", "deleting secret", "secretID", secretID) - _, err := m.client.GetSecret(ctx, &accessRequest) - return err == nil + return m.client.DeleteSecret(ctx, &deleteRequest) } diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go index 3ce7ad35a..ee1cb9fd8 100644 --- a/internal/credentials/gcp/secretmanager_test.go +++ b/internal/credentials/gcp/secretmanager_test.go @@ -113,7 +113,6 @@ func TestDeleteCredentials(t *testing.T) { m.projectID = defaultProjectID secretID := "some-secret-id" - clientMock.On("GetSecret", mock.Anything, mock.Anything).Return(&secretmanagerpb.Secret{}, nil).Once() clientMock.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) err := m.DeleteCredentials(context.Background(), secretID) From 27c3f38ea800d601c831207d7d6f651bab52a294 Mon Sep 17 00:00:00 2001 From: gr0 Date: Thu, 25 May 2023 17:30:35 +0200 Subject: [PATCH 18/23] fix: remove extra lines Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index f75ae72d7..52c8473cf 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -123,7 +123,6 @@ func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) Data: c, }, } - v, err := m.client.AddSecretVersion(ctx, addSecretVersionReq) if err != nil { return "", fmt.Errorf("creating secret version in GCP: %w", err) @@ -138,7 +137,6 @@ func (m *Manager) ReadCredentials(ctx context.Context, secretID string, creds an getSecretRequest := secretmanagerpb.AccessSecretVersionRequest{ Name: fmt.Sprintf("projects/%v/secrets/%v/versions/latest", m.projectID, secretID), } - result, err := m.client.AccessSecretVersion(ctx, &getSecretRequest) if err != nil { return fmt.Errorf("%w: path=%s", credentials.ErrNotFound, secretID) From fc8711377a95273d2c6f3825e92dd0e3e962dc52 Mon Sep 17 00:00:00 2001 From: gr0 Date: Fri, 26 May 2023 15:55:13 +0200 Subject: [PATCH 19/23] fix: improve docs and check for credentials reader configuration Signed-off-by: gr0 --- app/artifact-cas/cmd/main.go | 15 ++++++++++----- app/controlplane/README.md | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/artifact-cas/cmd/main.go b/app/artifact-cas/cmd/main.go index 02f327412..96563c92b 100644 --- a/app/artifact-cas/cmd/main.go +++ b/app/artifact-cas/cmd/main.go @@ -126,15 +126,20 @@ func main() { } func newCredentialsReader(conf *conf.Credentials, l log.Logger) (credentials.Reader, error) { - if c := conf.GetAwsSecretManager(); c != nil { - return newAWSCredentialsManager(c, l) + awsc, vaultc, gcpc := conf.GetAwsSecretManager(), conf.GetVault(), conf.GetGcpSecretManager() + if awsc == nil && vaultc == nil && gcpc == nil { + return nil, errors.New("no credentials manager configuration found") } - if c := conf.GetGcpSecretManager(); c != nil { - return newGCPCredentialsManager(c, l) + if awsc != nil { + return newAWSCredentialsManager(awsc, l) } - return newVaultCredentialsManager(conf.GetVault(), l) + if gcpc != nil { + return newGCPCredentialsManager(gcpc, l) + } + + return newVaultCredentialsManager(vaultc, l) } func newAWSCredentialsManager(conf *conf.Credentials_AWSSecretManager, l log.Logger) (*awssecrets.Manager, error) { diff --git a/app/controlplane/README.md b/app/controlplane/README.md index eff680698..438538cd4 100644 --- a/app/controlplane/README.md +++ b/app/controlplane/README.md @@ -20,7 +20,7 @@ The control plane has 4 main dependencies - OpenID Connect (OIDC) provider. Chainloop authentication backend is delegated to a OIDC provider (i.e Google, GitHub or [Auth0](https://auth0.com/)) for single sign on. - The persistance layer requires a [PostgreSQL](https://www.postgresql.org/) database. -- Sensitive information provided by the user such as OCI registry credentials is sent to a secret storage backend. Currently we support both [Hashicorp Vault](https://www.vaultproject.io/) and [AWS Secret Manager](https://aws.amazon.com/secrets-manager/). +- Sensitive information provided by the user such as OCI registry credentials is sent to a secret storage backend. Currently we support [Hashicorp Vault](https://www.vaultproject.io/), [AWS Secret Manager](https://aws.amazon.com/secrets-manager/) and [GCP Secret Manager](https://cloud.google.com/secret-manager). - In addition to those third party dependencies, the control plane also has a dependency on Chainloop own [Artifact CAS](../artifact-cas). It is used to upload the received attestation to the end-user storage backend. > NOTE: The control plane does not store attestation or artifact data, these get forwarded to the user storage backend through the Artifact CAS. From 0927225ff7ec7dc241b1bf7461cc644a6a1e69d6 Mon Sep 17 00:00:00 2001 From: gr0 Date: Fri, 26 May 2023 16:08:14 +0200 Subject: [PATCH 20/23] fix: improve tests and make the key empty Signed-off-by: gr0 --- internal/credentials/gcp/_fixtures/gcp_key.json | 13 ------------- internal/credentials/gcp/secretmanager.go | 9 +-------- internal/credentials/gcp/secretmanager_test.go | 8 +++++--- internal/credentials/gcp/testdata/key.txt | 1 + internal/credentials/gcp/testdata/test_gcp_key.json | 13 +++++++++++++ 5 files changed, 20 insertions(+), 24 deletions(-) delete mode 100644 internal/credentials/gcp/_fixtures/gcp_key.json create mode 100644 internal/credentials/gcp/testdata/key.txt create mode 100644 internal/credentials/gcp/testdata/test_gcp_key.json diff --git a/internal/credentials/gcp/_fixtures/gcp_key.json b/internal/credentials/gcp/_fixtures/gcp_key.json deleted file mode 100644 index c1f85ed62..000000000 --- a/internal/credentials/gcp/_fixtures/gcp_key.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "service_account", - "project_id": "chainloop-dev", - "private_key_id": "3739437f557d4d82283c04573865c508e6bc6038", - "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDTJ2KDLgiBjoNm\nfEkbZvBJvLSCXKBol5NYJXsqmyZNPoWWcvRlMsBUn5u1+ibucXPmjDtaekr1j3n5\nnnLY1HgMmS6BX7wE7f2aiHouIafTSHT04kw6khxkuYc7qpFTUKrwkH5rBsDsu3S9\nkZs1pv2PAc9Qr2FA3g9gGv+jtAhIk5vaqskGfsndtIpnx0IxCvfelwGERZ/XUrlD\nHkfAlA6tkLO+WbP76qez3d/qPh1ftIgVw+hOUSLLc8S9xoT41hkCyXqiA+ELzam7\nMrQr1jY6NX4ttVQt1+mad3v1nYnzJ4G91Ty7S80Mp8cVDtdWJM4aBeI4Q3/PyqBM\n5Ir8OP+BAgMBAAECggEAMJvdetNrE+Ap8brk3ZEJ+f+eEnCeYNWcDuu5+enznE6r\nVCIsjutrCVAg+XiX48ZsZwObWk3S2croyoUmbTIkXMoawZ+3We8rtZp7fgkzaFlC\ny2kZIVangKyRLDQs9mAYqf6pi5vnZ9gTnNxbPbOupXBGOI3XNqaoJXixpw735TTi\nk6qP85U6zYHCI+2QFD7cLt7CE2r/2yV61rSTByDY+uowq1R0kjNqX0J0XW529Rdh\nSlyzvjuBqzYuOM/0JpRwPXFbw6WK5MsRNkkDbjS2vyhM+1l9FDQG03ealx0FvnSb\nA8i93Dt7io+6yB7TDAhJAdHMNEXRVXD79fiKox8oUQKBgQD6LE2kjQ2N4+MtFwYL\nsoA9BRela0XEruyCxFCZl7YTka9A28G62hu0B+NW/VlgSjBzv0dxy0avlL+5xmrl\n4ISI0QJKuK/2ZSr00YU2OBoMN3UokA2mxVvtoKLgybZK5Lt7Nocq2V7b2o2epdcp\nAYK/O4wckvHOKnduuwFFluf+/QKBgQDYEmxaPord5DDVeROK7nuE4M/S+Wc9LlDD\n59R0hgZhZcZFzwKadH6zAuSZ7fLMdv4o1wD7smDE66wYJpPa2R5si9GEbiISWdaC\nu1ENxXF0JbApTPrdjWNynAooLrWq4adfWciEzxXBMRixXuruRPc4l5pEDtx74tAB\nWMxNfs5j1QKBgQCYc2EJMo+c9M9ejdY4UJmHFdBYFKvadIJaGcnIH0RsXm3+xywi\ncoFJTzlBrHfHjs5B6sFd3fMAUlQXoItJ9Gyvdza/VBaevv3TXM6hwMRWx4DUrBw1\nkbU4dJhtBV7Z+tMo/YyXFwmQTnnYwNUB/xKu+FmknANQkF5hkwHuZ0yO/QKBgQDR\nvDhe9PyY3IqmfIuCvXE6j3pMAPm8gnu1XhB1Ny90VXU7h/Cv+sqNew5peHbJD+wv\nulvi9chG/bikDLZSpZSJqsKqeLkr9PZrGeZYpsI1CuxPesC8VCUnN94IGScQg0+T\nF7SzbcxhJgYhDdCfjmQnE8mTrJVKz+Q2mnpd8uvmLQKBgQDdtpUdf5gmY8l8E8x/\nV3qRQt3+bVPn6wzVj/MtEmaqSxESQmXwoBxxabrhvZhxuueeEYm0FO7l9yCs/rCM\nf8LnTEHtOKEJ3DjirfreVB6KRBNTIrJLdWQr0A7VO4dqDnAHQlVrXGor0df7VO+u\nwoPesVoQ3NZgLdVmdMdSDF0xlA==\n-----END PRIVATE KEY-----\n", - "client_email": "chainloop-service-account@chainloop-dev.iam.gserviceaccount.com", - "client_id": "133229671234657229293", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/russell-service-account%40archipelo-dev.iam.gserviceaccount.com", - "universe_domain": "googleapis.com" - } \ No newline at end of file diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index 52c8473cf..b65996c12 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "io" - "os" "strings" secretmanager "cloud.google.com/go/secretmanager/apiv1" @@ -68,13 +67,7 @@ func NewManager(opts *NewManagerOpts) (*Manager, error) { logger := servicelogger.ScopedHelper(l, "credentials/gcp-secrets-manager") logger.Infow("msg", "configuring gcp secrets-manager", "projectID", opts.ProjectID) - // read credentials file - serviceAccountKey, err := os.ReadFile(opts.ServiceAccountKey) - if err != nil { - return nil, fmt.Errorf("error while reading auth key file: %w", err) - } - - cli, err := secretmanager.NewClient(context.TODO(), option.WithCredentialsJSON(serviceAccountKey)) + cli, err := secretmanager.NewClient(context.TODO(), option.WithCredentialsFile(opts.ServiceAccountKey)) if err != nil { return nil, fmt.Errorf("error while creating the client: %w", err) } diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go index ee1cb9fd8..cc8e7ef18 100644 --- a/internal/credentials/gcp/secretmanager_test.go +++ b/internal/credentials/gcp/secretmanager_test.go @@ -32,7 +32,7 @@ import ( const defaultOrgID = "test-org" const defaultProjectID = "1234-5678-9012" -const defaultServiceAccountKey string = "./_fixtures/gcp_key.json" +const defaultServiceAccountKey string = "./testdata/test_gcp_key.json" func TestNewManager(t *testing.T) { assert := assert.New(t) @@ -44,8 +44,10 @@ func TestNewManager(t *testing.T) { expectedError bool }{ {name: "missing projectID", projectID: "", serviceAccountKey: defaultServiceAccountKey, expectedError: true}, - {name: "missing authKey", projectID: defaultProjectID, serviceAccountKey: "", expectedError: true}, - {name: "valid manager", projectID: defaultProjectID, serviceAccountKey: defaultServiceAccountKey}, + {name: "missing service account key", projectID: defaultProjectID, serviceAccountKey: "", expectedError: true}, + {name: "invalid service account key", projectID: defaultProjectID, serviceAccountKey: defaultServiceAccountKey, expectedError: true}, + {name: "wrong service account key path", projectID: defaultProjectID, serviceAccountKey: "./non/existing/path/key.json", expectedError: true}, + {name: "wrong type of service account key", projectID: defaultProjectID, serviceAccountKey: "./testdata/key.txt", expectedError: true}, } for _, tc := range testCases { diff --git a/internal/credentials/gcp/testdata/key.txt b/internal/credentials/gcp/testdata/key.txt new file mode 100644 index 000000000..a739093a2 --- /dev/null +++ b/internal/credentials/gcp/testdata/key.txt @@ -0,0 +1 @@ +an empty key file for test \ No newline at end of file diff --git a/internal/credentials/gcp/testdata/test_gcp_key.json b/internal/credentials/gcp/testdata/test_gcp_key.json new file mode 100644 index 000000000..26f7113b4 --- /dev/null +++ b/internal/credentials/gcp/testdata/test_gcp_key.json @@ -0,0 +1,13 @@ +{ + "type": "", + "project_id": "", + "private_key_id": "", + "private_key": "", + "client_email": "", + "client_id": "", + "auth_uri": "", + "token_uri": "", + "auth_provider_x509_cert_url": "", + "client_x509_cert_url": "", + "universe_domain": "" + } \ No newline at end of file From 49cd080b929784be9558ae2434912d6fee2e0488 Mon Sep 17 00:00:00 2001 From: gr0 Date: Fri, 26 May 2023 16:14:52 +0200 Subject: [PATCH 21/23] fix: improve tests and use redacted key Signed-off-by: gr0 --- .../credentials/gcp/secretmanager_test.go | 2 +- .../gcp/testdata/test_gcp_key.json | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/credentials/gcp/secretmanager_test.go b/internal/credentials/gcp/secretmanager_test.go index cc8e7ef18..f0975e587 100644 --- a/internal/credentials/gcp/secretmanager_test.go +++ b/internal/credentials/gcp/secretmanager_test.go @@ -45,9 +45,9 @@ func TestNewManager(t *testing.T) { }{ {name: "missing projectID", projectID: "", serviceAccountKey: defaultServiceAccountKey, expectedError: true}, {name: "missing service account key", projectID: defaultProjectID, serviceAccountKey: "", expectedError: true}, - {name: "invalid service account key", projectID: defaultProjectID, serviceAccountKey: defaultServiceAccountKey, expectedError: true}, {name: "wrong service account key path", projectID: defaultProjectID, serviceAccountKey: "./non/existing/path/key.json", expectedError: true}, {name: "wrong type of service account key", projectID: defaultProjectID, serviceAccountKey: "./testdata/key.txt", expectedError: true}, + {name: "valid service account key", projectID: defaultProjectID, serviceAccountKey: defaultServiceAccountKey}, } for _, tc := range testCases { diff --git a/internal/credentials/gcp/testdata/test_gcp_key.json b/internal/credentials/gcp/testdata/test_gcp_key.json index 26f7113b4..75117b58f 100644 --- a/internal/credentials/gcp/testdata/test_gcp_key.json +++ b/internal/credentials/gcp/testdata/test_gcp_key.json @@ -1,13 +1,13 @@ { - "type": "", - "project_id": "", - "private_key_id": "", - "private_key": "", - "client_email": "", - "client_id": "", - "auth_uri": "", - "token_uri": "", - "auth_provider_x509_cert_url": "", - "client_x509_cert_url": "", - "universe_domain": "" - } \ No newline at end of file + "type": "service_account", + "project_id": "foo-bar", + "private_key_id": "1234", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDTJ2KDLgiBjoNm\nfEkbZvBJvLSCXKBol5NYJXsqmyZNPoWWcvRlMsBUn5u1+ibucXPmjDtaekr1j3n5\nnnLY1HgMmS6BX7wE7f2aiHouIafTSHT04kw6khxkuYc7qpFTUKrwkH5rBsDsu3S9\nkZs1pv2PAc9Qr2FA3g9gGv+jtAhIk5vaqskGfsndtIpnx0IxCvfelwGERZ/XUrlD\nHkfAlA6tkLO+WbP76qez3d/qPh1ftIgVw+hOUSLLc8S9xoT41hkCyXqiA+ELzam7\nMrQr1jY6NX4ttVQt1+mad3v1nYnzJ4G91Ty7S80Mp8cVDtdWJM4aBeI4Q3/PyqBM\n5Ir8OP+BAgMBAAECggEAMJvdetNrE+Ap8brk3ZEJ+f+eEnCeYNWcDuu5+enznE6r\nVCIsjutrCVAg+XiX48ZsZwObWk3S2croyoUmbTIkXMoawZ+3We8rtZp7fgkzaFlC\ny2kZIVangKyRLDQs9mAYqf6pi5vnZ9gTnNxbPbOupXBGOI3XNqaoJXixpw735TTi\nk6qP85U6zYHCI+2QFD7cLt7CE2r/2yV61rSTByDY+uowq1R0kjNqX0J0XW529Rdh\nSlyzvjuBqzYuOM/0JpRwPXFbw6WK5MsRNkkDbjS2vyhM+1l9FDQG03ealx0FvnSb\nA8i93Dt7io+6yB7TDAhJAdHMNEXRVXD79fiKox8oUQKBgQD6LE2kjQ2N4+MtFwYL\nsoA9BRela0XEruyCxFCZl7YTka9A28G62hu0B+NW/VlgSjBzv0dxy0avlL+5xmrl\n4ISI0QJKuK/2ZSr00YU2OBoMN3UokA2mxVvtoKLgybZK5Lt7Nocq2V7b2o2epdcp\nAYK/O4wckvHOKnduuwFFluf+/QKBgQDYEmxaPord5DDVeROK7nuE4M/S+Wc9LlDD\n59R0hgZhZcZFzwKadH6zAuSZ7fLMdv4o1wD7smDE66wYJpPa2R5si9GEbiISWdaC\nu1ENxXF0JbApTPrdjWNynAooLrWq4adfWciEzxXBMRixXuruRPc4l5pEDtx74tAB\nWMxNfs5j1QKBgQCYc2EJMo+c9M9ejdY4UJmHFdBYFKvadIJaGcnIH0RsXm3+xywi\ncoFJTzlBrHfHjs5B6sFd3fMAUlQXoItJ9Gyvdza/VBaevv3TXM6hwMRWx4DUrBw1\nkbU4dJhtBV7Z+tMo/YyXFwmQTnnYwNUB/xKu+FmknANQkF5hkwHuZ0yO/QKBgQDR\nvDhe9PyY3IqmfIuCvXE6j3pMAPm8gnu1XhB1Ny90VXU7h/Cv+sqNew5peHbJD+wv\nulvi9chG/bikDLZSpZSJqsKqeLkr9PZrGeZYpsI1CuxPesC8VCUnN94IGScQg0+T\nF7SzbcxhJgYhDdCfjmQnE8mTrJVKz+Q2mnpd8uvmLQKBgQDdtpUdf5gmY8l8E8x/\nV3qRQt3+bVPn6wzVj/MtEmaqSxESQmXwoBxxabrhvZjjjjeeEYm0FO7l9yCs/rCM\nf8LnTEHtOKEJ3DjirfreVB6KRBNTIrJLdWQr0A7VO4dqDnAHQlVrXGor0df7VO+u\nwoPesVoQ3NZgLdVmdMdSDF0xlA==\n-----END PRIVATE KEY-----\n", + "client_email": "bar.foo@foo.bar.com", + "client_id": "9876", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/foo-bra-account%40foo.bar.com", + "universe_domain": "googleapis.com" +} \ No newline at end of file From ec456df57ad61f1668559927438e89c61921be38 Mon Sep 17 00:00:00 2001 From: gr0 Date: Fri, 26 May 2023 16:36:25 +0200 Subject: [PATCH 22/23] fix: redact the key used in unit tests to make sure it is clear the key is redacted Signed-off-by: gr0 --- internal/credentials/gcp/testdata/test_gcp_key.json | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/internal/credentials/gcp/testdata/test_gcp_key.json b/internal/credentials/gcp/testdata/test_gcp_key.json index 75117b58f..42436c209 100644 --- a/internal/credentials/gcp/testdata/test_gcp_key.json +++ b/internal/credentials/gcp/testdata/test_gcp_key.json @@ -1,13 +1,5 @@ { + "comment": "this is not a valid service account key, it is meant for unit tests only", "type": "service_account", - "project_id": "foo-bar", - "private_key_id": "1234", - "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDTJ2KDLgiBjoNm\nfEkbZvBJvLSCXKBol5NYJXsqmyZNPoWWcvRlMsBUn5u1+ibucXPmjDtaekr1j3n5\nnnLY1HgMmS6BX7wE7f2aiHouIafTSHT04kw6khxkuYc7qpFTUKrwkH5rBsDsu3S9\nkZs1pv2PAc9Qr2FA3g9gGv+jtAhIk5vaqskGfsndtIpnx0IxCvfelwGERZ/XUrlD\nHkfAlA6tkLO+WbP76qez3d/qPh1ftIgVw+hOUSLLc8S9xoT41hkCyXqiA+ELzam7\nMrQr1jY6NX4ttVQt1+mad3v1nYnzJ4G91Ty7S80Mp8cVDtdWJM4aBeI4Q3/PyqBM\n5Ir8OP+BAgMBAAECggEAMJvdetNrE+Ap8brk3ZEJ+f+eEnCeYNWcDuu5+enznE6r\nVCIsjutrCVAg+XiX48ZsZwObWk3S2croyoUmbTIkXMoawZ+3We8rtZp7fgkzaFlC\ny2kZIVangKyRLDQs9mAYqf6pi5vnZ9gTnNxbPbOupXBGOI3XNqaoJXixpw735TTi\nk6qP85U6zYHCI+2QFD7cLt7CE2r/2yV61rSTByDY+uowq1R0kjNqX0J0XW529Rdh\nSlyzvjuBqzYuOM/0JpRwPXFbw6WK5MsRNkkDbjS2vyhM+1l9FDQG03ealx0FvnSb\nA8i93Dt7io+6yB7TDAhJAdHMNEXRVXD79fiKox8oUQKBgQD6LE2kjQ2N4+MtFwYL\nsoA9BRela0XEruyCxFCZl7YTka9A28G62hu0B+NW/VlgSjBzv0dxy0avlL+5xmrl\n4ISI0QJKuK/2ZSr00YU2OBoMN3UokA2mxVvtoKLgybZK5Lt7Nocq2V7b2o2epdcp\nAYK/O4wckvHOKnduuwFFluf+/QKBgQDYEmxaPord5DDVeROK7nuE4M/S+Wc9LlDD\n59R0hgZhZcZFzwKadH6zAuSZ7fLMdv4o1wD7smDE66wYJpPa2R5si9GEbiISWdaC\nu1ENxXF0JbApTPrdjWNynAooLrWq4adfWciEzxXBMRixXuruRPc4l5pEDtx74tAB\nWMxNfs5j1QKBgQCYc2EJMo+c9M9ejdY4UJmHFdBYFKvadIJaGcnIH0RsXm3+xywi\ncoFJTzlBrHfHjs5B6sFd3fMAUlQXoItJ9Gyvdza/VBaevv3TXM6hwMRWx4DUrBw1\nkbU4dJhtBV7Z+tMo/YyXFwmQTnnYwNUB/xKu+FmknANQkF5hkwHuZ0yO/QKBgQDR\nvDhe9PyY3IqmfIuCvXE6j3pMAPm8gnu1XhB1Ny90VXU7h/Cv+sqNew5peHbJD+wv\nulvi9chG/bikDLZSpZSJqsKqeLkr9PZrGeZYpsI1CuxPesC8VCUnN94IGScQg0+T\nF7SzbcxhJgYhDdCfjmQnE8mTrJVKz+Q2mnpd8uvmLQKBgQDdtpUdf5gmY8l8E8x/\nV3qRQt3+bVPn6wzVj/MtEmaqSxESQmXwoBxxabrhvZjjjjeeEYm0FO7l9yCs/rCM\nf8LnTEHtOKEJ3DjirfreVB6KRBNTIrJLdWQr0A7VO4dqDnAHQlVrXGor0df7VO+u\nwoPesVoQ3NZgLdVmdMdSDF0xlA==\n-----END PRIVATE KEY-----\n", - "client_email": "bar.foo@foo.bar.com", - "client_id": "9876", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/foo-bra-account%40foo.bar.com", - "universe_domain": "googleapis.com" + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDTJ2KDLgiBjoNm\nfEkbZvBJvLSCXKBol5NYJXsqmyZNPoWWcvRlMsBUn5u1+ibucXPmjDtaekr1j3n5\nnnLY1HgMmS6BX7wE7f2aiHouIafTSHT04kw6khxkuYc7qpFTUKrwkH5rBsDsu3S9\nkZs1pv2PAc9Qr2FA3g9gGv+jtAhIk5vaqskGfsndtIpnx0IxCvfelwGERZ/XUrlD\nHkfAlA6tkLO+WbP76qez3d/qPh1ftIgVw+hOUSLLc8S9xoT41hkCyXqiA+ELzam7\nMrQr1jY6NX4ttVQt1+mad3v1nYnzJ4G91Ty7S80Mp8cVDtdWJM4aBeI4Q3/PyqBM\n5Ir8OP+BAgMBAAECggEAMJvdetNrE+Ap8brk3ZEJ+f+eEnCeYNWcDuu5+enznE6r\nVCIsjutrCVAg+XiX48ZsZwObWk3S2croyoUmbTIkXMoawZ+3We8rtZp7fgkzaFlC\ny2kZIVangKyRLDQs9mAYqf6pi5vnZ9gTnNxbPbOupXBGOI3XNqaoJXixpw735TTi\nk6qP85U6zYHCI+2QFD7cLt7CE2r/2yV61rSTByDY+uowq1R0kjNqX0J0XW529Rdh\nSlyzvjuBqzYuOM/0JpRwPXFbw6WK5MsRNkkDbjS2vyhM+1l9FDQG03ealx0FvnSb\nA8i93Dt7io+6yB7TDAhJAdHMNEXRVXD79fiKox8oUQKBgQD6LE2kjQ2N4+MtFwYL\nsoA9BRela0XEruyCxFCZl7YTka9A28G62hu0B+NW/VlgSjBzv0dxy0avlL+5xmrl\n4ISI0QJKuK/2ZSr00YU2OBoMN3UokA2mxVvtoKLgybZK5Lt7Nocq2V7b2o2epdcp\nAYK/O4wckvHOKnduuwFFluf+/QKBgQDYEmxaPord5DDVeROK7nuE4M/S+Wc9LlDD\n59R0hgZhZcZFzwKadH6zAuSZ7fLMdv4o1wD7smDE66wYJpPa2R5si9GEbiISWdaC\nu1ENxXF0JbApTPrdjWNynAooLrWq4adfWciEzxXBMRixXuruRPc4l5pEDtx74tAB\nWMxNfs5j1QKBgQCYc2EJMo+c9M9ejdY4UJmHFdBYFKvadIJaGcnIH0RsXm3+xywi\ncoFJTzlBrHfHjs5B6sFd3fMAUlQXoItJ9Gyvdza/VBaevv3TXM6hwMRWx4DUrBw1\nkbU4dJhtBV7Z+tMo/YyXFwmQTnnYwNUB/xKu+FmknANQkF5hkwHuZ0yO/QKBgQDR\nvDhe9PyY3IqmfIuCvXE6j3pMAPm8gnu1XhB1Ny90VXU7h/Cv+sqNew5peHbJD+wv\nulvi9chG/bikDLZSpZSJqsKqeLkr9PZrGeZYpsI1CuxPesC8VCUnN94IGScQg0+T\nF7SzbcxhJgYhDdCfjmQnE8mTrJVKz+Q2mnpd8uvmLQKBgQDdtpUdf5gmY8l8E8x/\nV3qRQt3+bVPn6wzVj/MtEmaqSxESQmXwoBxxabrhvZjjjjeeEYm0FO7l9yCs/rCM\nf8LnTEHtOKEJ3DjirfreVB6KRBNTIrJLdWQr0A7VO4dqDnAHQlVrXGor0df7VO+u\nwoPesVoQ3NZgLdVmdMdSDF0xlA==\n-----END PRIVATE KEY-----\n" } \ No newline at end of file From 335789ba37b8f870dd63e74e587afc53e2045853 Mon Sep 17 00:00:00 2001 From: gr0 Date: Fri, 26 May 2023 16:37:02 +0200 Subject: [PATCH 23/23] fix: typo correct Signed-off-by: gr0 --- internal/credentials/gcp/secretmanager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/credentials/gcp/secretmanager.go b/internal/credentials/gcp/secretmanager.go index b65996c12..0d06fcbdf 100644 --- a/internal/credentials/gcp/secretmanager.go +++ b/internal/credentials/gcp/secretmanager.go @@ -107,7 +107,7 @@ func (m *Manager) SaveCredentials(ctx context.Context, orgID string, creds any) if err != nil { return "", fmt.Errorf("creating secret in GCP: %w", err) } - m.logger.Infow("msg", "created new secrect", "secretID", secretID) + m.logger.Infow("msg", "created new secret", "secretID", secretID) // once the secret is created store it as the newest version addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{