From 9c1676d0adf159df3a63e77a415c93a44b63c8cd Mon Sep 17 00:00:00 2001 From: Julien Duchesne Date: Sat, 11 Apr 2020 12:23:53 -0400 Subject: [PATCH] Add target ID feature. Different credentials with same ID on different targets --- README.md | 7 +++++++ cli/root.go | 4 +++- credentials/credentials.go | 11 +++++++++++ credentials/credentials_mock.go | 14 ++++++++++++++ go.mod | 4 ++-- go.sum | 21 +++++++++++---------- sync/target.go | 6 +++--- targets/jenkins.go | 12 ++++++------ 8 files changed, 57 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 56ae8d3..b40bfe2 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,9 @@ sources: - secret_id: arn:aws:secretsmanager:us-west-2:123456789012:secret:production/MyAwesomeAppSecret-a1b2c3 stop_on_error: true # If true, will completely stop the process if an operation fails. Otherwise, continues anyways target_parallelism: 3 # Number of target on which to sync creds at the same time +credentials_to_delete: # These will be removed from every target + - number1 + - number2 targets: jenkins: - name: toolsjenkins @@ -71,16 +74,20 @@ The source's value must either be a list or a map in the following formats (JSON ```yaml # list - id: my_cred + target_id: id_on_target # Optional, defaults to the ID description: a description ... - id: my_other_cred + target_id: id_on_target # Optional, defaults to the ID ... # map my_cred: + target_id: id_on_target # Optional, defaults to the ID description: a description ... my_other_cred: + target_id: id_on_target # Optional, defaults to the ID ... ``` diff --git a/cli/root.go b/cli/root.go index 7fd93ca..b5e4b34 100644 --- a/cli/root.go +++ b/cli/root.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials/stscreds" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" "github.com/mitchellh/mapstructure" @@ -56,7 +57,8 @@ var rootCmd = &cobra.Command{ if strings.HasPrefix(configurationFile, "s3://") { sess := session.Must(session.NewSessionWithOptions(session.Options{ - SharedConfigState: session.SharedConfigEnable, + SharedConfigState: session.SharedConfigEnable, + AssumeRoleTokenProvider: stscreds.StdinTokenProvider, })) s3Client := s3.New(sess) splitS3Path, err := url.Parse(configurationFile) diff --git a/credentials/credentials.go b/credentials/credentials.go index ab76fc9..1706ab1 100644 --- a/credentials/credentials.go +++ b/credentials/credentials.go @@ -13,6 +13,7 @@ import ( type Credentials interface { BaseValidate() error GetID() string + GetTargetID() string ShouldSync(targetName string, targetTags map[string]string) bool ToString(bool) string Validate() error @@ -30,6 +31,7 @@ type Base struct { NoSync bool `mapstructure:"no_sync"` TargetName string `mapstructure:"target"` TargetTags targetTagsMatcher `mapstructure:"target_tags"` + TargetID string `mapstructure:"target_id"` // Field set by constructor CredType string @@ -71,6 +73,15 @@ func (credBase *Base) GetID() string { return credBase.ID } +// GetTargetID returns a credentials' Target ID (Essentially, the name that the credentials should have on a target) +// This is helpful to have different credentials with the same target ID (on different targets) +func (credBase *Base) GetTargetID() string { + if credBase.TargetID != "" { + return credBase.TargetID + } + return credBase.GetID() +} + // ShouldSync returns, given a target's name and tags, if a credentials should be synced to that target // This is based on various credentials attributes such as the TargetTags DoMatch and DontMatch attributes func (credBase *Base) ShouldSync(targetName string, targetTags map[string]string) bool { diff --git a/credentials/credentials_mock.go b/credentials/credentials_mock.go index f47ed4d..cff89b2 100644 --- a/credentials/credentials_mock.go +++ b/credentials/credentials_mock.go @@ -60,6 +60,20 @@ func (mr *MockCredentialsMockRecorder) GetID() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetID", reflect.TypeOf((*MockCredentials)(nil).GetID)) } +// GetTargetID mocks base method +func (m *MockCredentials) GetTargetID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTargetID") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetTargetID indicates an expected call of GetTargetID +func (mr *MockCredentialsMockRecorder) GetTargetID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTargetID", reflect.TypeOf((*MockCredentials)(nil).GetTargetID)) +} + // ShouldSync mocks base method func (m *MockCredentials) ShouldSync(targetName string, targetTags map[string]string) bool { m.ctrl.T.Helper() diff --git a/go.mod b/go.mod index 9979cfa..1fcfb33 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( github.com/hashicorp/go-multierror v1.1.0 github.com/mitchellh/mapstructure v1.2.2 github.com/sirupsen/logrus v1.5.0 - github.com/spf13/cobra v0.0.7 - github.com/spf13/viper v1.6.2 + github.com/spf13/cobra v1.0.0 + github.com/spf13/viper v1.6.3 github.com/stretchr/testify v1.5.1 gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index fb17afd..9f959f3 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aws/aws-sdk-go v1.30.4 h1:dpQgypC3rld2Uuz+/2u+0nbfmmyEWxau6v1hdAlvoc8= -github.com/aws/aws-sdk-go v1.30.4/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.30.7 h1:IaXfqtioP6p9SFAnNfsqdNczbR5UNbYqvcZUSsCAdTY= github.com/aws/aws-sdk-go v1.30.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -15,6 +13,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -43,6 +42,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -51,8 +51,6 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -62,6 +60,7 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienduchesne/gojenkins v2.1.0+incompatible h1:B5MG08Pwfjys8y/5i9x4psqCZOMJXf2+oBC4nhiistc= @@ -87,6 +86,9 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= @@ -108,8 +110,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -122,20 +122,21 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= -github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= -github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= diff --git a/sync/target.go b/sync/target.go index 8fe34e5..57ac77f 100644 --- a/sync/target.go +++ b/sync/target.go @@ -30,7 +30,7 @@ func (config *Configuration) DeleteListOfCredentials(target targets.Target) erro func (config *Configuration) UpdateListOfCredentials(target targets.Target, listOfCredentials []credentials.Credentials) error { isSynced := func(id string) bool { for _, credentials := range listOfCredentials { - if credentials.GetID() == id { + if credentials.GetTargetID() == id { return true } } @@ -38,9 +38,9 @@ func (config *Configuration) UpdateListOfCredentials(target targets.Target, list } for _, credentials := range listOfCredentials { - log.Infof("[%s] Syncing %s", target.GetName(), credentials.GetID()) + log.Infof("[%s] Syncing %s", target.GetName(), credentials.GetTargetID()) if err := target.UpdateCredentials(credentials); err != nil { - err = fmt.Errorf("Failed to send credentials with ID %s to %s: %v", credentials.GetID(), target.GetName(), err) + err = fmt.Errorf("Failed to send credentials with ID %s to %s: %v", credentials.GetTargetID(), target.GetName(), err) if config.StopOnError { return err } diff --git a/targets/jenkins.go b/targets/jenkins.go index 1008dd6..acbd6b1 100644 --- a/targets/jenkins.go +++ b/targets/jenkins.go @@ -85,8 +85,8 @@ func (jenkins *JenkinsTarget) UpdateCredentials(cred credentials.Credentials) er if jenkinsCred == nil { return fmt.Errorf("Unable to create jenkins credentials from %s", cred.GetID()) } - if HasCredential(jenkins, cred.GetID()) { - return jenkins.credentialsManager.Update(credentialsDomain, cred.GetID(), jenkinsCred) + if HasCredential(jenkins, cred.GetTargetID()) { + return jenkins.credentialsManager.Update(credentialsDomain, cred.GetTargetID(), jenkinsCred) } return jenkins.credentialsManager.Add(credentialsDomain, jenkinsCred) } @@ -104,7 +104,7 @@ func toJenkinsCredential(creds credentials.Credentials) interface{} { case *credentials.AmazonWebServicesCredentials: castCreds := creds.(*credentials.AmazonWebServicesCredentials) return &gojenkins.AmazonWebServicesCredentials{ - ID: creds.GetID(), + ID: creds.GetTargetID(), Description: castCreds.GetDescriptionOrID(), AccessKey: castCreds.AccessKey, SecretKey: castCreds.SecretKey, @@ -114,14 +114,14 @@ func toJenkinsCredential(creds credentials.Credentials) interface{} { case *credentials.SecretTextCredentials: castCreds := creds.(*credentials.SecretTextCredentials) return &gojenkins.StringCredentials{ - ID: creds.GetID(), + ID: creds.GetTargetID(), Description: castCreds.GetDescriptionOrID(), Secret: castCreds.Secret, } case *credentials.UsernamePasswordCredentials: castCreds := creds.(*credentials.UsernamePasswordCredentials) return &gojenkins.UsernameCredentials{ - ID: castCreds.GetID(), + ID: castCreds.GetTargetID(), Description: castCreds.GetDescriptionOrID(), Username: castCreds.Username, Password: castCreds.Password, @@ -129,7 +129,7 @@ func toJenkinsCredential(creds credentials.Credentials) interface{} { case *credentials.SSHCredentials: castCreds := creds.(*credentials.SSHCredentials) return &gojenkins.SSHCredentials{ - ID: castCreds.GetID(), + ID: castCreds.GetTargetID(), Description: castCreds.GetDescriptionOrID(), Username: castCreds.Username, Passphrase: castCreds.Passphrase,