Skip to content

Commit 4e59429

Browse files
feat: Add support for secrets manager environment variables (#287)
1 parent 24e62d8 commit 4e59429

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

package/lib/compileFunctions.js

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ module.exports = {
4949
_.get(funcObject, 'timeout') || _.get(this, 'serverless.service.provider.timeout') || '60s';
5050
funcTemplate.properties.environmentVariables =
5151
this.provider.getConfiguredEnvironment(funcObject);
52+
funcTemplate.properties.secretEnvironmentVariables =
53+
this.provider.getConfiguredSecrets(funcObject);
5254

5355
if (!funcTemplate.properties.serviceAccountEmail) {
5456
delete funcTemplate.properties.serviceAccountEmail;
@@ -80,6 +82,9 @@ module.exports = {
8082
if (!_.size(funcTemplate.properties.environmentVariables)) {
8183
delete funcTemplate.properties.environmentVariables;
8284
}
85+
if (!_.size(funcTemplate.properties.secretEnvironmentVariables)) {
86+
delete funcTemplate.properties.secretEnvironmentVariables;
87+
}
8388

8489
funcTemplate.properties.labels = _.assign(
8590
{},

package/lib/compileFunctions.test.js

+102
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,108 @@ describe('CompileFunctions', () => {
507507
});
508508
});
509509

510+
it('should set the secret environment variables based on the function configuration', () => {
511+
googlePackage.serverless.service.functions = {
512+
func1: {
513+
handler: 'func1',
514+
secrets: {
515+
TEST_SECRET: {
516+
secret: 'secret',
517+
version: 'latest',
518+
},
519+
},
520+
events: [{ http: 'foo' }],
521+
},
522+
};
523+
524+
const compiledResources = [
525+
{
526+
type: 'gcp-types/cloudfunctions-v1:projects.locations.functions',
527+
name: 'my-service-dev-func1',
528+
properties: {
529+
parent: 'projects/myProject/locations/us-central1',
530+
runtime: 'nodejs10',
531+
function: 'my-service-dev-func1',
532+
entryPoint: 'func1',
533+
availableMemoryMb: 256,
534+
secretEnvironmentVariables: [
535+
{
536+
key: 'TEST_SECRET',
537+
secret: 'secret',
538+
version: 'latest',
539+
},
540+
],
541+
timeout: '60s',
542+
sourceArchiveUrl: 'gs://sls-my-service-dev-12345678/some-path/artifact.zip',
543+
httpsTrigger: {
544+
url: 'foo',
545+
},
546+
labels: {},
547+
},
548+
},
549+
];
550+
551+
return googlePackage.compileFunctions().then(() => {
552+
expect(consoleLogStub.calledOnce).toEqual(true);
553+
expect(
554+
googlePackage.serverless.service.provider.compiledConfigurationTemplate.resources
555+
).toEqual(compiledResources);
556+
});
557+
});
558+
559+
it('should merge the secret environment variables on the provider configuration and function definition', () => {
560+
googlePackage.serverless.service.functions = {
561+
func1: {
562+
handler: 'func1',
563+
secrets: {
564+
TEST_SECRET: { secret: 'secret1', version: 'latest' },
565+
TEST_SECRET2: { secret: 'secret2', version: 'latest' },
566+
},
567+
events: [{ http: 'foo' }],
568+
},
569+
};
570+
googlePackage.serverless.service.provider.secrets = {
571+
TEST_SECRET: { secret: 'secretbase', version: 'latest' },
572+
TEST_SECRET_PROVIDER: { secret: 'secretprovider', version: 'latest' },
573+
};
574+
575+
const compiledResources = [
576+
{
577+
type: 'gcp-types/cloudfunctions-v1:projects.locations.functions',
578+
name: 'my-service-dev-func1',
579+
properties: {
580+
parent: 'projects/myProject/locations/us-central1',
581+
runtime: 'nodejs10',
582+
function: 'my-service-dev-func1',
583+
entryPoint: 'func1',
584+
availableMemoryMb: 256,
585+
secretEnvironmentVariables: [
586+
{ key: 'TEST_SECRET', secret: 'secret1', version: 'latest' },
587+
{ key: 'TEST_SECRET2', secret: 'secret2', version: 'latest' },
588+
{ key: 'TEST_SECRET_PROVIDER', secret: 'secretprovider', version: 'latest' },
589+
],
590+
timeout: '60s',
591+
sourceArchiveUrl: 'gs://sls-my-service-dev-12345678/some-path/artifact.zip',
592+
httpsTrigger: {
593+
url: 'foo',
594+
},
595+
labels: {},
596+
},
597+
},
598+
];
599+
600+
return googlePackage.compileFunctions().then(() => {
601+
expect(consoleLogStub.calledOnce).toEqual(true);
602+
expect(
603+
googlePackage.serverless.service.provider.compiledConfigurationTemplate.resources
604+
).toEqual(compiledResources);
605+
expect(googlePackage.serverless.service.provider.secrets).toEqual({
606+
TEST_SECRET: { secret: 'secretbase', version: 'latest' },
607+
TEST_SECRET_PROVIDER: { secret: 'secretprovider', version: 'latest' },
608+
});
609+
});
610+
});
611+
510612
it('should compile "http" events properly', () => {
511613
googlePackage.serverless.service.functions = {
512614
func1: {

provider/googleProvider.js

+38
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,29 @@ class GoogleProvider {
9292
},
9393
additionalProperties: false,
9494
},
95+
cloudFunctionSecretEnvironmentVariables: {
96+
type: 'object',
97+
patternProperties: {
98+
'^[a-zA-Z0-9_]+$': {
99+
type: 'object',
100+
properties: {
101+
projectId: {
102+
type: 'string',
103+
minLength: 1,
104+
},
105+
secret: {
106+
type: 'string',
107+
pattern: '^[a-zA-Z0-9_-]+$',
108+
},
109+
version: {
110+
type: 'string',
111+
pattern: '^(latest|[0-9.]+)$',
112+
},
113+
},
114+
required: ['secret', 'version'],
115+
},
116+
},
117+
},
95118
cloudFunctionVpcEgress: {
96119
enum: ['ALL', 'ALL_TRAFFIC', 'PRIVATE', 'PRIVATE_RANGES_ONLY'],
97120
},
@@ -119,6 +142,7 @@ class GoogleProvider {
119142
memorySize: { $ref: '#/definitions/cloudFunctionMemory' }, // Can be overridden by function configuration
120143
timeout: { type: 'string' }, // Can be overridden by function configuration
121144
environment: { $ref: '#/definitions/cloudFunctionEnvironmentVariables' }, // Can be overridden by function configuration
145+
secrets: { $ref: '#/definitions/cloudFunctionSecretEnvironmentVariables' }, // Can be overridden by function configuration
122146
vpc: { type: 'string' }, // Can be overridden by function configuration
123147
vpcEgress: { $ref: '#/definitions/cloudFunctionVpcEgress' }, // Can be overridden by function configuration
124148
labels: { $ref: '#/definitions/resourceManagerLabels' }, // Can be overridden by function configuration
@@ -133,6 +157,7 @@ class GoogleProvider {
133157
timeout: { type: 'string' }, // Override provider configuration
134158
minInstances: { type: 'number' },
135159
environment: { $ref: '#/definitions/cloudFunctionEnvironmentVariables' }, // Override provider configuration
160+
secrets: { $ref: '#/definitions/cloudFunctionSecretEnvironmentVariables' }, // Can be overridden by function configuration
136161
vpc: { type: 'string' }, // Override provider configuration
137162
vpcEgress: { $ref: '#/definitions/cloudFunctionVpcEgress' }, // Can be overridden by function configuration
138163
labels: { $ref: '#/definitions/resourceManagerLabels' }, // Override provider configuration
@@ -279,6 +304,19 @@ class GoogleProvider {
279304
);
280305
}
281306

307+
getConfiguredSecrets(funcObject) {
308+
const providerSecrets = _.get(this, 'serverless.service.provider.secrets', {});
309+
const secrets = _.merge({}, providerSecrets, funcObject.secrets);
310+
311+
const keys = Object.keys(secrets).sort();
312+
return keys.map((key) => {
313+
return {
314+
key,
315+
...secrets[key],
316+
};
317+
});
318+
}
319+
282320
getConfiguredEnvironment(funcObject) {
283321
return _.merge(
284322
{},

0 commit comments

Comments
 (0)