@friggframework/devtools 2.0.0--canary.461.b8c7c6b.0 → 2.0.0--canary.461.0afe1c4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - KMS key creation or discovery
|
|
8
8
|
* - KMS key configuration for field-level encryption
|
|
9
9
|
* - IAM permissions for KMS operations
|
|
10
|
-
* - KMS
|
|
10
|
+
* - KMS key policy configuration for Lambda execution role
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
const { InfrastructureBuilder, ValidationResult } = require('../shared/base-builder');
|
|
@@ -73,28 +73,21 @@ class KmsBuilder extends InfrastructureBuilder {
|
|
|
73
73
|
console.log(' Creating new KMS key...');
|
|
74
74
|
result.resources = this.createKmsKey(appDefinition);
|
|
75
75
|
result.environment.KMS_KEY_ARN = { 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] };
|
|
76
|
-
result.pluginConfig.kmsGrants = {
|
|
77
|
-
kmsKeyId: { 'Fn::GetAtt': ['FriggKMSKey', 'Arn'] },
|
|
78
|
-
};
|
|
79
76
|
console.log(' ✅ KMS key resources created');
|
|
80
77
|
} else {
|
|
81
78
|
// Use discovered KMS key
|
|
82
79
|
const kmsKeyId = discoveredResources.defaultKmsKeyId || '${env:AWS_DISCOVERY_KMS_KEY_ID}';
|
|
83
80
|
console.log(` Using ${discoveredResources.defaultKmsKeyId ? 'discovered' : 'environment variable'} KMS key`);
|
|
84
81
|
result.environment.KMS_KEY_ARN = kmsKeyId;
|
|
85
|
-
result.pluginConfig.kmsGrants = { kmsKeyId };
|
|
86
82
|
}
|
|
87
83
|
|
|
88
|
-
// Add IAM permissions
|
|
84
|
+
// Add IAM permissions for Lambda role
|
|
89
85
|
result.iamStatements.push({
|
|
90
86
|
Effect: 'Allow',
|
|
91
|
-
Action: ['kms:GenerateDataKey', 'kms:Decrypt'],
|
|
87
|
+
Action: ['kms:GenerateDataKey', 'kms:Decrypt', 'kms:Encrypt', 'kms:DescribeKey'],
|
|
92
88
|
Resource: result.environment.KMS_KEY_ARN,
|
|
93
89
|
});
|
|
94
90
|
|
|
95
|
-
// Enable KMS grants plugin
|
|
96
|
-
result.plugins.push('serverless-kms-grants');
|
|
97
|
-
|
|
98
91
|
console.log(`[${this.name}] ✅ KMS configuration completed`);
|
|
99
92
|
return result;
|
|
100
93
|
}
|
|
@@ -110,12 +103,13 @@ class KmsBuilder extends InfrastructureBuilder {
|
|
|
110
103
|
UpdateReplacePolicy: 'Retain',
|
|
111
104
|
Properties: {
|
|
112
105
|
Description: 'Frigg Field-Level Encryption Key for ${self:service}-${self:provider.stage}',
|
|
106
|
+
EnableKeyRotation: true,
|
|
113
107
|
KeyPolicy: {
|
|
114
108
|
Version: '2012-10-17',
|
|
115
109
|
Id: 'key-policy-1',
|
|
116
110
|
Statement: [
|
|
117
111
|
{
|
|
118
|
-
Sid: '
|
|
112
|
+
Sid: 'AllowRootAccountAdmin',
|
|
119
113
|
Effect: 'Allow',
|
|
120
114
|
Principal: {
|
|
121
115
|
AWS: {
|
|
@@ -126,7 +120,7 @@ class KmsBuilder extends InfrastructureBuilder {
|
|
|
126
120
|
Resource: '*',
|
|
127
121
|
},
|
|
128
122
|
{
|
|
129
|
-
Sid: '
|
|
123
|
+
Sid: 'AllowLambdaService',
|
|
130
124
|
Effect: 'Allow',
|
|
131
125
|
Principal: {
|
|
132
126
|
Service: 'lambda.amazonaws.com',
|
|
@@ -143,6 +137,20 @@ class KmsBuilder extends InfrastructureBuilder {
|
|
|
143
137
|
},
|
|
144
138
|
},
|
|
145
139
|
},
|
|
140
|
+
{
|
|
141
|
+
Sid: 'AllowLambdaExecutionRole',
|
|
142
|
+
Effect: 'Allow',
|
|
143
|
+
Principal: {
|
|
144
|
+
AWS: { 'Fn::GetAtt': ['IamRoleLambdaExecution', 'Arn'] },
|
|
145
|
+
},
|
|
146
|
+
Action: [
|
|
147
|
+
'kms:Decrypt',
|
|
148
|
+
'kms:GenerateDataKey',
|
|
149
|
+
'kms:Encrypt',
|
|
150
|
+
'kms:DescribeKey',
|
|
151
|
+
],
|
|
152
|
+
Resource: '*',
|
|
153
|
+
},
|
|
146
154
|
],
|
|
147
155
|
},
|
|
148
156
|
Tags: [
|
|
@@ -148,7 +148,7 @@ describe('KmsBuilder', () => {
|
|
|
148
148
|
const result = await kmsBuilder.build(appDefinition, discoveredResources);
|
|
149
149
|
|
|
150
150
|
expect(result.environment.KMS_KEY_ARN).toBe('arn:aws:kms:us-east-1:123456:key/abc-123');
|
|
151
|
-
expect(result.pluginConfig.kmsGrants
|
|
151
|
+
expect(result.pluginConfig.kmsGrants).toBeUndefined();
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
it('should add IAM permissions for KMS operations', async () => {
|
|
@@ -167,12 +167,12 @@ describe('KmsBuilder', () => {
|
|
|
167
167
|
expect(result.iamStatements).toHaveLength(1);
|
|
168
168
|
expect(result.iamStatements[0]).toEqual({
|
|
169
169
|
Effect: 'Allow',
|
|
170
|
-
Action: ['kms:GenerateDataKey', 'kms:Decrypt'],
|
|
170
|
+
Action: ['kms:GenerateDataKey', 'kms:Decrypt', 'kms:Encrypt', 'kms:DescribeKey'],
|
|
171
171
|
Resource: 'arn:aws:kms:us-east-1:123456:key/abc',
|
|
172
172
|
});
|
|
173
173
|
});
|
|
174
174
|
|
|
175
|
-
it('should
|
|
175
|
+
it('should NOT use serverless-kms-grants plugin (deprecated)', async () => {
|
|
176
176
|
const appDefinition = {
|
|
177
177
|
encryption: {
|
|
178
178
|
fieldLevelEncryptionMethod: 'kms',
|
|
@@ -185,7 +185,8 @@ describe('KmsBuilder', () => {
|
|
|
185
185
|
|
|
186
186
|
const result = await kmsBuilder.build(appDefinition, discoveredResources);
|
|
187
187
|
|
|
188
|
-
expect(result.plugins).toContain('serverless-kms-grants');
|
|
188
|
+
expect(result.plugins).not.toContain('serverless-kms-grants');
|
|
189
|
+
expect(result.pluginConfig.kmsGrants).toBeUndefined();
|
|
189
190
|
});
|
|
190
191
|
});
|
|
191
192
|
|
|
@@ -316,6 +317,28 @@ describe('KmsBuilder', () => {
|
|
|
316
317
|
expect(lambdaStatement.Action).toContain('kms:GenerateDataKey');
|
|
317
318
|
expect(lambdaStatement.Action).toContain('kms:Decrypt');
|
|
318
319
|
});
|
|
320
|
+
|
|
321
|
+
it('should create key policy allowing Lambda execution role direct access', async () => {
|
|
322
|
+
const appDefinition = {
|
|
323
|
+
encryption: {
|
|
324
|
+
fieldLevelEncryptionMethod: 'kms',
|
|
325
|
+
createResourceIfNoneFound: true,
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const result = await kmsBuilder.build(appDefinition, {});
|
|
330
|
+
|
|
331
|
+
const policy = result.resources.FriggKMSKey.Properties.KeyPolicy;
|
|
332
|
+
const roleStatement = policy.Statement.find(s => s.Sid === 'AllowLambdaExecutionRole');
|
|
333
|
+
|
|
334
|
+
expect(roleStatement).toBeDefined();
|
|
335
|
+
expect(roleStatement.Effect).toBe('Allow');
|
|
336
|
+
expect(roleStatement.Principal.AWS).toEqual({ 'Fn::GetAtt': ['IamRoleLambdaExecution', 'Arn'] });
|
|
337
|
+
expect(roleStatement.Action).toContain('kms:GenerateDataKey');
|
|
338
|
+
expect(roleStatement.Action).toContain('kms:Decrypt');
|
|
339
|
+
expect(roleStatement.Action).toContain('kms:Encrypt');
|
|
340
|
+
expect(roleStatement.Action).toContain('kms:DescribeKey');
|
|
341
|
+
});
|
|
319
342
|
});
|
|
320
343
|
|
|
321
344
|
describe('Error handling', () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.461.
|
|
4
|
+
"version": "2.0.0--canary.461.0afe1c4.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@babel/eslint-parser": "^7.18.9",
|
|
12
12
|
"@babel/parser": "^7.25.3",
|
|
13
13
|
"@babel/traverse": "^7.25.3",
|
|
14
|
-
"@friggframework/schemas": "2.0.0--canary.461.
|
|
15
|
-
"@friggframework/test": "2.0.0--canary.461.
|
|
14
|
+
"@friggframework/schemas": "2.0.0--canary.461.0afe1c4.0",
|
|
15
|
+
"@friggframework/test": "2.0.0--canary.461.0afe1c4.0",
|
|
16
16
|
"@hapi/boom": "^10.0.1",
|
|
17
17
|
"@inquirer/prompts": "^5.3.8",
|
|
18
18
|
"axios": "^1.7.2",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"serverless-http": "^2.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@friggframework/eslint-config": "2.0.0--canary.461.
|
|
38
|
-
"@friggframework/prettier-config": "2.0.0--canary.461.
|
|
37
|
+
"@friggframework/eslint-config": "2.0.0--canary.461.0afe1c4.0",
|
|
38
|
+
"@friggframework/prettier-config": "2.0.0--canary.461.0afe1c4.0",
|
|
39
39
|
"aws-sdk-client-mock": "^4.1.0",
|
|
40
40
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
41
41
|
"jest": "^30.1.3",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "0afe1c4c284cd5ee939bdcb7ef011f36098f76fc"
|
|
74
74
|
}
|