@deployfoundation/foundation-deploy 0.2.51 → 0.2.53
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.
- package/README.md +4 -1
- package/dist/bin/app.js +6 -3
- package/dist/bin/foundation-deploy.js +141 -305
- package/dist/bin/release-account.js +1 -0
- package/dist/chunk-1pww63wd.js +301 -0
- package/dist/chunk-3614v9rr.js +907 -0
- package/dist/chunk-5wgwscd0.js +4 -0
- package/dist/{chunk-gnz747z2.js → chunk-96fjaysn.js} +204 -884
- package/dist/chunk-fjdgxw8h.js +516 -0
- package/dist/chunk-jf5rw6h4.js +1117 -0
- package/dist/chunk-m76jt5rc.js +376 -0
- package/dist/chunk-mh1206ne.js +1764 -0
- package/dist/chunk-nvsj7bbw.js +259 -0
- package/dist/chunk-p7zkm4pp.js +151 -0
- package/dist/chunk-pxhftba1.js +336 -0
- package/dist/{chunk-efqdhd2e.js → chunk-spq5kr1t.js} +333 -90
- package/dist/chunk-tey0gh86.js +38 -0
- package/dist/src/index.js +17 -13
- package/package.json +3 -1
- package/src/deploy/cli.ts +71 -0
- package/src/deploy/crm.ts +491 -0
- package/src/deploy/runtime-secret.ts +9 -0
- package/src/stacks/agent-stack.ts +68 -11
- package/src/stacks/api-stack.ts +340 -87
- package/src/stacks/data-stack.ts +27 -1
- package/src/stacks/secret-bearing-reads.ts +131 -0
package/src/stacks/data-stack.ts
CHANGED
|
@@ -16,7 +16,8 @@ export interface FoundationDataProps extends cdk.StackProps {
|
|
|
16
16
|
* FoundationData — the durable layer: one CMK, two S3 buckets (config +
|
|
17
17
|
* skills, and channel documents), two always-present DynamoDB tables, an
|
|
18
18
|
* optional CRM table, an optional proxy-only Upwork approval table, an optional
|
|
19
|
-
* retained Upwork OAuth secret,
|
|
19
|
+
* retained Upwork OAuth secret, the optional key for a company's own CRM, and
|
|
20
|
+
* the Secrets Manager entries.
|
|
20
21
|
* The two always-present DynamoDB tables use
|
|
21
22
|
* different access patterns: `FoundationTable` is `pk` (S) only:
|
|
22
23
|
* dedupe rows, the Codex credential lease and the thread→session index, every
|
|
@@ -53,6 +54,12 @@ export class FoundationData extends cdk.Stack {
|
|
|
53
54
|
public readonly upworkApprovalTable?: dynamodb.Table;
|
|
54
55
|
/** Short-lived OOB request-token state; gateway-only and destroyed with the opt-in. */
|
|
55
56
|
public readonly etradePendingTable?: dynamodb.Table;
|
|
57
|
+
/**
|
|
58
|
+
* The `crm/1` key, present only with `crm.provider` kind `http`. Other stacks
|
|
59
|
+
* reach it by its fixed name, never through this object, so switching back to
|
|
60
|
+
* `dynamodb` can delete it without a cross-stack export holding it in place.
|
|
61
|
+
*/
|
|
62
|
+
public readonly crmHttpSecret?: secretsmanager.Secret;
|
|
56
63
|
public readonly secrets: {
|
|
57
64
|
signing: secretsmanager.ISecret;
|
|
58
65
|
slackApp: secretsmanager.ISecret;
|
|
@@ -230,6 +237,25 @@ export class FoundationData extends cdk.Stack {
|
|
|
230
237
|
})
|
|
231
238
|
: undefined;
|
|
232
239
|
|
|
240
|
+
// The key for a company's own CRM (`crm.provider` kind `http`): empty
|
|
241
|
+
// until `foundation-deploy crm-key` writes `{ api_key }`, and until then
|
|
242
|
+
// the CRM proxy answers `unconfigured`. Like the Otter key it is destroyed
|
|
243
|
+
// with the opt-in: a rollback to `dynamodb` must not strand a fixed-name
|
|
244
|
+
// secret that a later switch back to `http` could not create again, and
|
|
245
|
+
// the CRM issues a fresh key in seconds.
|
|
246
|
+
this.crmHttpSecret =
|
|
247
|
+
provisionsIntegration(props.instance, "crm") && props.instance.crm.provider.kind === "http"
|
|
248
|
+
? new secretsmanager.Secret(this, "CrmHttpSecret", {
|
|
249
|
+
secretName: names.secretCrmHttp,
|
|
250
|
+
description: `crm/1 key for ${display}'s CRM ({ api_key }); written by foundation-deploy crm-key, read only by the CRM proxy`,
|
|
251
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
252
|
+
generateSecretString: {
|
|
253
|
+
secretStringTemplate: "{}",
|
|
254
|
+
generateStringKey: "placeholder",
|
|
255
|
+
},
|
|
256
|
+
})
|
|
257
|
+
: undefined;
|
|
258
|
+
|
|
233
259
|
// Unlike the disposable Otter API key, the Upwork OAuth secret carries
|
|
234
260
|
// client credentials plus refresh state. Retaining it makes a deploy safe
|
|
235
261
|
// and leaves manually entered client credentials intact.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads that AWS's `ReadOnlyAccess` grants whose RESPONSES carry secrets in
|
|
3
|
+
* plaintext: environment variables, user data, connection properties, request
|
|
4
|
+
* headers, issued tokens. Both shell-reachable agent roles deny every one of
|
|
5
|
+
* them (`FoundationAgent.secretBearingReadsPolicy`), so "read-only" never means
|
|
6
|
+
* "can read the credentials that write".
|
|
7
|
+
*
|
|
8
|
+
* Found 2026-10-26 in a company account: three Lambdas held a read-write
|
|
9
|
+
* MongoDB connection string in their environment, and sampled WAF requests
|
|
10
|
+
* held the web app's admin bearer tokens. Either one turned the read-only role
|
|
11
|
+
* into a write path.
|
|
12
|
+
*
|
|
13
|
+
* Judged against `ReadOnlyAccess` v190 (2026-09-24). The rule for adding an
|
|
14
|
+
* action: its response can contain a value someone typed in as configuration
|
|
15
|
+
* (env, user data, connection or job arguments, hosted config), a credential
|
|
16
|
+
* AWS mints for the caller, or another caller's request. Data-plane reads
|
|
17
|
+
* (S3 objects, DynamoDB items, queue messages, log events) are a different
|
|
18
|
+
* question, decided separately: see docs/capabilities/aws-readonly.md.
|
|
19
|
+
*
|
|
20
|
+
* What stays readable for diagnosis: CloudWatch Logs (Insights included),
|
|
21
|
+
* metrics, alarms, X-Ray, CloudTrail, every `Describe*`/`List*` not named here,
|
|
22
|
+
* stack events and outputs, SSM parameter NAMES, and Lambda's event source
|
|
23
|
+
* mappings, aliases, concurrency and policies.
|
|
24
|
+
*
|
|
25
|
+
* Every entry is an exact action name, never a wildcard, so a reviewer can
|
|
26
|
+
* check each one against the service authorization reference.
|
|
27
|
+
*/
|
|
28
|
+
export const SECRET_BEARING_READ_ACTIONS: readonly string[] = [
|
|
29
|
+
// WAF sampled requests return full request headers, Authorization included.
|
|
30
|
+
"wafv2:GetSampledRequests",
|
|
31
|
+
"waf:GetSampledRequests",
|
|
32
|
+
"waf-regional:GetSampledRequests",
|
|
33
|
+
|
|
34
|
+
// Lambda: function configuration includes `Environment.Variables`, and
|
|
35
|
+
// GetFunction / GetLayerVersion add a presigned code download URL. List
|
|
36
|
+
// calls return the same configuration for every function or version.
|
|
37
|
+
"lambda:GetFunction",
|
|
38
|
+
"lambda:GetFunctionConfiguration",
|
|
39
|
+
"lambda:ListFunctions",
|
|
40
|
+
"lambda:ListVersionsByFunction",
|
|
41
|
+
"lambda:GetLayerVersion",
|
|
42
|
+
"lambda:GetLayerVersionByArn",
|
|
43
|
+
|
|
44
|
+
// Container and build configuration: plaintext environment variables.
|
|
45
|
+
"ecs:DescribeTaskDefinition",
|
|
46
|
+
"apprunner:DescribeService",
|
|
47
|
+
"batch:DescribeJobDefinitions",
|
|
48
|
+
"batch:DescribeJobs",
|
|
49
|
+
"codebuild:BatchGetProjects",
|
|
50
|
+
"codebuild:BatchGetBuilds",
|
|
51
|
+
"codebuild:BatchGetBuildBatches",
|
|
52
|
+
|
|
53
|
+
// Amplify apps and branches carry environment variables and basic-auth
|
|
54
|
+
// credentials; backend environments carry deployment settings.
|
|
55
|
+
"amplify:GetApp",
|
|
56
|
+
"amplify:ListApps",
|
|
57
|
+
"amplify:GetBranch",
|
|
58
|
+
"amplify:ListBranches",
|
|
59
|
+
"amplify:GetBackendEnvironment",
|
|
60
|
+
|
|
61
|
+
// Elastic Beanstalk environment properties are its environment variables.
|
|
62
|
+
"elasticbeanstalk:DescribeConfigurationSettings",
|
|
63
|
+
|
|
64
|
+
// EC2 user data (instance attribute and launch template versions).
|
|
65
|
+
"ec2:DescribeLaunchTemplateVersions",
|
|
66
|
+
"ec2:DescribeInstanceAttribute",
|
|
67
|
+
|
|
68
|
+
// SSM parameter VALUES. Denied for plain String parameters too: teams
|
|
69
|
+
// store secrets as String by mistake, and with the account's default
|
|
70
|
+
// `aws/ssm` key a SecureString can decrypt through the same call.
|
|
71
|
+
// DescribeParameters (names, types, versions) stays readable.
|
|
72
|
+
"ssm:GetParameter",
|
|
73
|
+
"ssm:GetParameters",
|
|
74
|
+
"ssm:GetParametersByPath",
|
|
75
|
+
"ssm:GetParameterHistory",
|
|
76
|
+
|
|
77
|
+
// CloudFormation template bodies can hold literal secrets and parameter
|
|
78
|
+
// defaults. Denied: DescribeStacks, DescribeStackEvents and
|
|
79
|
+
// DescribeStackResources answer the diagnosis questions without them.
|
|
80
|
+
"cloudformation:GetTemplate",
|
|
81
|
+
|
|
82
|
+
// AppConfig hosted configuration content is application configuration.
|
|
83
|
+
"appconfig:GetConfiguration",
|
|
84
|
+
"appconfig:GetHostedConfigurationVersion",
|
|
85
|
+
|
|
86
|
+
// Glue job default arguments and connection properties (JDBC user and
|
|
87
|
+
// password when not in Secrets Manager); dev endpoints carry job arguments.
|
|
88
|
+
// v190 does not grant GetConnection(s); they are named anyway because AWS
|
|
89
|
+
// revises the policy without notice and these return the password.
|
|
90
|
+
"glue:GetJob",
|
|
91
|
+
"glue:GetJobs",
|
|
92
|
+
"glue:BatchGetJobs",
|
|
93
|
+
"glue:GetConnection",
|
|
94
|
+
"glue:GetConnections",
|
|
95
|
+
"glue:GetDevEndpoint",
|
|
96
|
+
"glue:GetDevEndpoints",
|
|
97
|
+
"glue:BatchGetDevEndpoints",
|
|
98
|
+
|
|
99
|
+
// SageMaker container `Environment` maps on models and jobs.
|
|
100
|
+
"sagemaker:DescribeModel",
|
|
101
|
+
"sagemaker:DescribeTrainingJob",
|
|
102
|
+
"sagemaker:DescribeProcessingJob",
|
|
103
|
+
"sagemaker:DescribeTransformJob",
|
|
104
|
+
|
|
105
|
+
// Data Pipeline definitions hold activity fields, database passwords included.
|
|
106
|
+
"datapipeline:GetPipelineDefinition",
|
|
107
|
+
|
|
108
|
+
// AppSync: API key values, and HTTP data source authorization config.
|
|
109
|
+
"appsync:ListApiKeys",
|
|
110
|
+
"appsync:GetDataSource",
|
|
111
|
+
"appsync:ListDataSources",
|
|
112
|
+
|
|
113
|
+
// Kinesis Data Analytics / Managed Flink environment properties.
|
|
114
|
+
"kinesisanalytics:DescribeApplication",
|
|
115
|
+
|
|
116
|
+
// Lightsail bucket access keys and container service environment.
|
|
117
|
+
"lightsail:GetBucketAccessKeys",
|
|
118
|
+
"lightsail:GetContainerServices",
|
|
119
|
+
"lightsail:GetContainerServiceDeployments",
|
|
120
|
+
|
|
121
|
+
// OpsWorks app environment variables and stack custom JSON.
|
|
122
|
+
"opsworks:DescribeApps",
|
|
123
|
+
"opsworks:DescribeStacks",
|
|
124
|
+
|
|
125
|
+
// Calls that MINT a credential rather than describe one.
|
|
126
|
+
"cognito-identity:GetCredentialsForIdentity",
|
|
127
|
+
"cognito-identity:GetOpenIdToken",
|
|
128
|
+
"cognito-identity:GetOpenIdTokenForDeveloperIdentity",
|
|
129
|
+
"connect:GetFederationToken",
|
|
130
|
+
"codeartifact:GetAuthorizationToken",
|
|
131
|
+
];
|