5
5
"fmt"
6
6
"regexp"
7
7
"strings"
8
+ "sync"
8
9
9
10
"secrets-init/pkg/secrets" //nolint:gci
10
11
@@ -15,6 +16,13 @@ import (
15
16
secretspb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" //nolint:gci
16
17
)
17
18
19
+ var fullSecretRe = regexp .MustCompile (`projects/[^/]+/secrets/[^/+](/version/[^/+])?` )
20
+
21
+ type result struct {
22
+ Env string
23
+ Err error
24
+ }
25
+
18
26
// SecretsProvider Google Cloud secrets provider
19
27
type SecretsProvider struct {
20
28
sm SecretsManagerAPI
@@ -53,40 +61,79 @@ func NewGoogleSecretsProvider(ctx context.Context, projectID string) (secrets.Pr
53
61
func (sp SecretsProvider ) ResolveSecrets (ctx context.Context , vars []string ) ([]string , error ) {
54
62
envs := make ([]string , 0 , len (vars ))
55
63
56
- fullSecretRe := regexp .MustCompile ("projects/[^/]+/secrets/[^/+](/version/[^/+])?" )
64
+ // Create a channel to collect the results
65
+ results := make (chan result , len (vars ))
57
66
67
+ // Start a goroutine for each secret
68
+ var wg sync.WaitGroup
58
69
for _ , env := range vars {
59
- kv := strings .Split (env , "=" )
60
- key , value := kv [0 ], kv [1 ]
61
- if strings .HasPrefix (value , "gcp:secretmanager:" ) {
62
- // construct valid secret name
63
- name := strings .TrimPrefix (value , "gcp:secretmanager:" )
64
-
65
- isLong := fullSecretRe .MatchString (name )
66
-
67
- if ! isLong {
68
- if sp .projectID == "" {
69
- return vars , errors .Errorf ("failed to get secret \" %s\" from Google Secret Manager (unknown project)" , name )
70
+ wg .Add (1 )
71
+ go func (env string ) {
72
+ defer wg .Done ()
73
+ select {
74
+ case <- ctx .Done ():
75
+ results <- result {Err : ctx .Err ()}
76
+ return
77
+ default :
78
+ val , err := sp .processEnvironmentVariable (ctx , env )
79
+ if err != nil {
80
+ results <- result {Err : err }
81
+ return
70
82
}
71
- name = fmt . Sprintf ( "projects/%s/secrets/%s" , sp . projectID , name )
83
+ results <- result { Env : val }
72
84
}
85
+ }(env )
86
+ }
73
87
74
- // if no version specified add latest
75
- if ! strings .Contains (name , "/versions/" ) {
76
- name += "/versions/latest"
77
- }
78
- // get secret value
79
- req := & secretspb.AccessSecretVersionRequest {
80
- Name : name ,
81
- }
82
- secret , err := sp .sm .AccessSecretVersion (ctx , req )
83
- if err != nil {
84
- return vars , errors .Wrap (err , "failed to get secret from Google Secret Manager" )
85
- }
86
- env = key + "=" + string (secret .Payload .GetData ())
88
+ // Start another goroutine to close the results channel when all fetch goroutines are done
89
+ go func () {
90
+ wg .Wait ()
91
+ close (results )
92
+ }()
93
+
94
+ // Collect the results
95
+ for res := range results {
96
+ if res .Err != nil {
97
+ return vars , res .Err
87
98
}
88
- envs = append (envs , env )
99
+ envs = append (envs , res . Env )
89
100
}
90
101
91
102
return envs , nil
92
103
}
104
+
105
+ // processEnvironmentVariable processes the environment variable and replaces the value with the secret value
106
+ func (sp SecretsProvider ) processEnvironmentVariable (ctx context.Context , env string ) (string , error ) {
107
+ kv := strings .Split (env , "=" )
108
+ key , value := kv [0 ], kv [1 ]
109
+ if ! strings .HasPrefix (value , "gcp:secretmanager:" ) {
110
+ return env , nil
111
+ }
112
+
113
+ // construct valid secret name
114
+ name := strings .TrimPrefix (value , "gcp:secretmanager:" )
115
+
116
+ isLong := fullSecretRe .MatchString (name )
117
+
118
+ if ! isLong {
119
+ if sp .projectID == "" {
120
+ return "" , errors .Errorf ("failed to get secret \" %s\" from Google Secret Manager (unknown project)" , name )
121
+ }
122
+ name = fmt .Sprintf ("projects/%s/secrets/%s" , sp .projectID , name )
123
+ }
124
+
125
+ // if no version specified add latest
126
+ if ! strings .Contains (name , "/versions/" ) {
127
+ name += "/versions/latest"
128
+ }
129
+
130
+ // get secret value
131
+ req := & secretspb.AccessSecretVersionRequest {
132
+ Name : name ,
133
+ }
134
+ secret , err := sp .sm .AccessSecretVersion (ctx , req )
135
+ if err != nil {
136
+ return "" , fmt .Errorf ("failed to get secret from Google Secret Manager: %w" , err )
137
+ }
138
+ return key + "=" + string (secret .Payload .GetData ()), nil
139
+ }
0 commit comments