@prism-d1/cli 1.2.0 → 1.4.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.
Files changed (181) hide show
  1. package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +2 -2
  2. package/dist/assets/infra/bin/app.ts +61 -37
  3. package/dist/assets/infra/lib/constructs/security-agent-construct.ts +35 -30
  4. package/dist/assets/infra/lib/metrics-pipeline-stack.ts +2 -110
  5. package/dist/assets/infra/lib/security-agent-resources.ts +136 -0
  6. package/dist/assets/infra/lib/security-agent-stack.ts +69 -0
  7. package/dist/assets/pentest-cdk/bin/app.ts +12 -0
  8. package/dist/assets/pentest-cdk/cdk.json +7 -0
  9. package/dist/assets/pentest-cdk/lib/pentest-target-stack.ts +206 -0
  10. package/dist/assets/pentest-cdk/package.json +18 -0
  11. package/dist/assets/pentest-cdk/tsconfig.json +12 -0
  12. package/dist/src/aws/advice.d.ts +33 -0
  13. package/dist/src/aws/advice.d.ts.map +1 -0
  14. package/dist/src/aws/advice.js +174 -0
  15. package/dist/src/aws/advice.js.map +1 -0
  16. package/dist/src/aws/check.d.ts +64 -0
  17. package/dist/src/aws/check.d.ts.map +1 -0
  18. package/dist/src/aws/check.js +269 -0
  19. package/dist/src/aws/check.js.map +1 -0
  20. package/dist/src/aws/connect.d.ts +65 -0
  21. package/dist/src/aws/connect.d.ts.map +1 -0
  22. package/dist/src/aws/connect.js +250 -0
  23. package/dist/src/aws/connect.js.map +1 -0
  24. package/dist/src/aws/connection.d.ts +67 -0
  25. package/dist/src/aws/connection.d.ts.map +1 -0
  26. package/dist/src/aws/connection.js +137 -0
  27. package/dist/src/aws/connection.js.map +1 -0
  28. package/dist/src/aws/recommend.d.ts +70 -0
  29. package/dist/src/aws/recommend.d.ts.map +1 -0
  30. package/dist/src/aws/recommend.js +244 -0
  31. package/dist/src/aws/recommend.js.map +1 -0
  32. package/dist/src/aws/run-check.d.ts +31 -0
  33. package/dist/src/aws/run-check.d.ts.map +1 -0
  34. package/dist/src/aws/run-check.js +91 -0
  35. package/dist/src/aws/run-check.js.map +1 -0
  36. package/dist/src/codewatch/results.d.ts +155 -4
  37. package/dist/src/codewatch/results.d.ts.map +1 -1
  38. package/dist/src/codewatch/results.js +12 -2
  39. package/dist/src/codewatch/results.js.map +1 -1
  40. package/dist/src/commands/_top/version.d.ts +62 -0
  41. package/dist/src/commands/_top/version.d.ts.map +1 -0
  42. package/dist/src/commands/_top/version.js +175 -0
  43. package/dist/src/commands/_top/version.js.map +1 -0
  44. package/dist/src/commands/aws/check.d.ts +25 -0
  45. package/dist/src/commands/aws/check.d.ts.map +1 -0
  46. package/dist/src/commands/aws/check.js +42 -0
  47. package/dist/src/commands/aws/check.js.map +1 -0
  48. package/dist/src/commands/aws/connect.d.ts +16 -0
  49. package/dist/src/commands/aws/connect.d.ts.map +1 -0
  50. package/dist/src/commands/aws/connect.js +39 -0
  51. package/dist/src/commands/aws/connect.js.map +1 -0
  52. package/dist/src/commands/aws/recommend.d.ts +12 -0
  53. package/dist/src/commands/aws/recommend.d.ts.map +1 -0
  54. package/dist/src/commands/aws/recommend.js +21 -0
  55. package/dist/src/commands/aws/recommend.js.map +1 -0
  56. package/dist/src/commands/bedrock-protection/scan-account.d.ts.map +1 -1
  57. package/dist/src/commands/bedrock-protection/scan-account.js +14 -35
  58. package/dist/src/commands/bedrock-protection/scan-account.js.map +1 -1
  59. package/dist/src/commands/bedrock-protection/scan-org.d.ts.map +1 -1
  60. package/dist/src/commands/bedrock-protection/scan-org.js +12 -5
  61. package/dist/src/commands/bedrock-protection/scan-org.js.map +1 -1
  62. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts +12 -6
  63. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts.map +1 -1
  64. package/dist/src/commands/bootstrapper/setup-otel-sync.js +18 -409
  65. package/dist/src/commands/bootstrapper/setup-otel-sync.js.map +1 -1
  66. package/dist/src/commands/enable/codeburn.d.ts +59 -0
  67. package/dist/src/commands/enable/codeburn.d.ts.map +1 -0
  68. package/dist/src/commands/enable/codeburn.js +531 -0
  69. package/dist/src/commands/enable/codeburn.js.map +1 -0
  70. package/dist/src/commands/enable/security.d.ts +41 -0
  71. package/dist/src/commands/enable/security.d.ts.map +1 -0
  72. package/dist/src/commands/enable/security.js +128 -0
  73. package/dist/src/commands/enable/security.js.map +1 -0
  74. package/dist/src/commands/export/otel.d.ts +31 -0
  75. package/dist/src/commands/export/otel.d.ts.map +1 -0
  76. package/dist/src/commands/export/otel.js +52 -0
  77. package/dist/src/commands/export/otel.js.map +1 -0
  78. package/dist/src/commands/security/code-review.d.ts +22 -0
  79. package/dist/src/commands/security/code-review.d.ts.map +1 -0
  80. package/dist/src/commands/security/code-review.js +44 -0
  81. package/dist/src/commands/security/code-review.js.map +1 -0
  82. package/dist/src/commands/security/findings.d.ts +15 -0
  83. package/dist/src/commands/security/findings.d.ts.map +1 -0
  84. package/dist/src/commands/security/findings.js +33 -0
  85. package/dist/src/commands/security/findings.js.map +1 -0
  86. package/dist/src/commands/security/pentest.d.ts +18 -0
  87. package/dist/src/commands/security/pentest.d.ts.map +1 -0
  88. package/dist/src/commands/security/pentest.js +33 -0
  89. package/dist/src/commands/security/pentest.js.map +1 -0
  90. package/dist/src/commands/security/threat-model.d.ts +16 -0
  91. package/dist/src/commands/security/threat-model.d.ts.map +1 -0
  92. package/dist/src/commands/security/threat-model.js +25 -0
  93. package/dist/src/commands/security/threat-model.js.map +1 -0
  94. package/dist/src/commands/security/threats.d.ts +12 -0
  95. package/dist/src/commands/security/threats.d.ts.map +1 -0
  96. package/dist/src/commands/security/threats.js +24 -0
  97. package/dist/src/commands/security/threats.js.map +1 -0
  98. package/dist/src/commands/securityagent/setup.d.ts +19 -5
  99. package/dist/src/commands/securityagent/setup.d.ts.map +1 -1
  100. package/dist/src/commands/securityagent/setup.js +25 -189
  101. package/dist/src/commands/securityagent/setup.js.map +1 -1
  102. package/dist/src/dashboard/aws.d.ts +39 -0
  103. package/dist/src/dashboard/aws.d.ts.map +1 -0
  104. package/dist/src/dashboard/aws.js +35 -0
  105. package/dist/src/dashboard/aws.js.map +1 -0
  106. package/dist/src/dashboard/codewatch.d.ts.map +1 -1
  107. package/dist/src/dashboard/codewatch.js +2 -1
  108. package/dist/src/dashboard/codewatch.js.map +1 -1
  109. package/dist/src/dashboard/page.d.ts.map +1 -1
  110. package/dist/src/dashboard/page.js +193 -5
  111. package/dist/src/dashboard/page.js.map +1 -1
  112. package/dist/src/dashboard/payload.d.ts +11 -5
  113. package/dist/src/dashboard/payload.d.ts.map +1 -1
  114. package/dist/src/dashboard/payload.js +7 -2
  115. package/dist/src/dashboard/payload.js.map +1 -1
  116. package/dist/src/dashboard/security.d.ts +130 -0
  117. package/dist/src/dashboard/security.d.ts.map +1 -0
  118. package/dist/src/dashboard/security.js +144 -0
  119. package/dist/src/dashboard/security.js.map +1 -0
  120. package/dist/src/dashboard/setup.d.ts +15 -0
  121. package/dist/src/dashboard/setup.d.ts.map +1 -1
  122. package/dist/src/dashboard/setup.js +20 -3
  123. package/dist/src/dashboard/setup.js.map +1 -1
  124. package/dist/src/dashboard/usage.js +1 -1
  125. package/dist/src/dashboard/usage.js.map +1 -1
  126. package/dist/src/index.d.ts.map +1 -1
  127. package/dist/src/index.js +9 -2
  128. package/dist/src/index.js.map +1 -1
  129. package/dist/src/security/cfn-diff.d.ts +57 -0
  130. package/dist/src/security/cfn-diff.d.ts.map +1 -0
  131. package/dist/src/security/cfn-diff.js +112 -0
  132. package/dist/src/security/cfn-diff.js.map +1 -0
  133. package/dist/src/security/errors.d.ts +45 -0
  134. package/dist/src/security/errors.d.ts.map +1 -0
  135. package/dist/src/security/errors.js +116 -0
  136. package/dist/src/security/errors.js.map +1 -0
  137. package/dist/src/security/marker.d.ts +46 -0
  138. package/dist/src/security/marker.d.ts.map +1 -0
  139. package/dist/src/security/marker.js +120 -0
  140. package/dist/src/security/marker.js.map +1 -0
  141. package/dist/src/security/pentest-dockerfile.d.ts +8 -0
  142. package/dist/src/security/pentest-dockerfile.d.ts.map +1 -0
  143. package/dist/src/security/pentest-dockerfile.js +163 -0
  144. package/dist/src/security/pentest-dockerfile.js.map +1 -0
  145. package/dist/src/security/pentest.d.ts +233 -0
  146. package/dist/src/security/pentest.d.ts.map +1 -0
  147. package/dist/src/security/pentest.js +1057 -0
  148. package/dist/src/security/pentest.js.map +1 -0
  149. package/dist/src/security/repo.d.ts +25 -0
  150. package/dist/src/security/repo.d.ts.map +1 -0
  151. package/dist/src/security/repo.js +38 -0
  152. package/dist/src/security/repo.js.map +1 -0
  153. package/dist/src/security/review.d.ts +202 -0
  154. package/dist/src/security/review.d.ts.map +1 -0
  155. package/dist/src/security/review.js +706 -0
  156. package/dist/src/security/review.js.map +1 -0
  157. package/dist/src/security/setup.d.ts +209 -0
  158. package/dist/src/security/setup.d.ts.map +1 -0
  159. package/dist/src/security/setup.js +742 -0
  160. package/dist/src/security/setup.js.map +1 -0
  161. package/dist/src/security/threat-model.d.ts +133 -0
  162. package/dist/src/security/threat-model.d.ts.map +1 -0
  163. package/dist/src/security/threat-model.js +653 -0
  164. package/dist/src/security/threat-model.js.map +1 -0
  165. package/dist/src/utils/audit-account.d.ts +50 -0
  166. package/dist/src/utils/audit-account.d.ts.map +1 -0
  167. package/dist/src/utils/audit-account.js +69 -0
  168. package/dist/src/utils/audit-account.js.map +1 -0
  169. package/dist/src/utils/audit-iam.d.ts +1 -1
  170. package/dist/src/utils/audit-iam.d.ts.map +1 -1
  171. package/dist/src/utils/audit-iam.js +11 -7
  172. package/dist/src/utils/audit-iam.js.map +1 -1
  173. package/dist/src/utils/exec.d.ts +6 -0
  174. package/dist/src/utils/exec.d.ts.map +1 -1
  175. package/dist/src/utils/exec.js +12 -1
  176. package/dist/src/utils/exec.js.map +1 -1
  177. package/dist/src/utils/otel-sync-schedule.d.ts +19 -0
  178. package/dist/src/utils/otel-sync-schedule.d.ts.map +1 -1
  179. package/dist/src/utils/otel-sync-schedule.js +24 -2
  180. package/dist/src/utils/otel-sync-schedule.js.map +1 -1
  181. package/package.json +3 -3
@@ -0,0 +1,206 @@
1
+ /**
2
+ * The temporary pentest TARGET environment, deployed per run by
3
+ * `prism-cli security pentest` (dockerfile adapter). Generalized from the
4
+ * hand-run spike stack (removed once this replaced it); see
5
+ * docs/DESIGN-prism-cli-pentest.md. Test target: cli/test/fixtures/pentest-sample.
6
+ *
7
+ * Private VPC only: private isolated subnets, no public subnet, no internet
8
+ * gateway, no NAT, no 0.0.0.0/0 ingress anywhere. The app runs on Fargate
9
+ * behind an INTERNAL ALB; the pentest agent's ENI reaches it over local VPC
10
+ * routing. VPC endpoints (ECR api+dkr, S3 gateway, CloudWatch Logs) let Fargate
11
+ * run with no internet path.
12
+ *
13
+ * Context (all from `cdk -c key=value`, set by the adapter):
14
+ * slug run id; names the stack's resources and the private zone
15
+ * appDir absolute path to the Docker build context -> image asset
16
+ * dockerfile Dockerfile path relative to appDir (default: Dockerfile)
17
+ * port container port the app listens on
18
+ * healthPath ALB health-check path
19
+ * zoneName private hosted-zone name (host is app.<zoneName>)
20
+ * ttlHours hours from synth for the prism:expires-at tag
21
+ */
22
+ import * as cdk from 'aws-cdk-lib';
23
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
24
+ import * as ecs from 'aws-cdk-lib/aws-ecs';
25
+ import * as ecrAssets from 'aws-cdk-lib/aws-ecr-assets';
26
+ import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
27
+ import * as iam from 'aws-cdk-lib/aws-iam';
28
+ import * as logs from 'aws-cdk-lib/aws-logs';
29
+ import * as route53 from 'aws-cdk-lib/aws-route53';
30
+ import * as targets from 'aws-cdk-lib/aws-route53-targets';
31
+ import * as s3 from 'aws-cdk-lib/aws-s3';
32
+ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
33
+ import { Construct } from 'constructs';
34
+
35
+ const ALB_PORT = 80;
36
+
37
+ /** A JSON context value (the adapter passes env, secrets and actor ARNs this way); absent = fallback. */
38
+ function ctxJson<T>(scope: Construct, key: string, fallback: T): T {
39
+ const v = scope.node.tryGetContext(key);
40
+ if (v === undefined || v === null || v === '') return fallback;
41
+ return (typeof v === 'string' ? JSON.parse(v) : v) as T;
42
+ }
43
+
44
+ /** A Secrets Manager ARN with its random 6-character suffix is complete; without it, partial. */
45
+ const isCompleteSecretArn = (arn: string) => /-[A-Za-z0-9]{6}$/.test(arn);
46
+
47
+ function ctxStr(scope: Construct, key: string, fallback?: string): string {
48
+ const v = scope.node.tryGetContext(key);
49
+ if (v === undefined || v === null || v === '') {
50
+ if (fallback !== undefined) return fallback;
51
+ throw new Error(`pentest-cdk: required context "${key}" is not set`);
52
+ }
53
+ return String(v);
54
+ }
55
+
56
+ export class PentestTargetStack extends cdk.Stack {
57
+ constructor(scope: Construct, id: string, props: cdk.StackProps) {
58
+ super(scope, id, props);
59
+
60
+ const slug = ctxStr(this, 'slug');
61
+ const appDir = ctxStr(this, 'appDir');
62
+ const port = Number(ctxStr(this, 'port', '8080'));
63
+ const healthPath = ctxStr(this, 'healthPath', '/health');
64
+ const zoneName = ctxStr(this, 'zoneName', `${slug}.prism.internal`);
65
+ const ttlHours = Number(ctxStr(this, 'ttlHours', '24'));
66
+ const logGroupName = `/aws/securityagent/prism-pentest-${slug}`;
67
+
68
+ cdk.Tags.of(this).add('prism:purpose', 'pentest');
69
+ cdk.Tags.of(this).add('prism:pentest-run', slug);
70
+ cdk.Tags.of(this).add('prism:expires-at', new Date(Date.now() + ttlHours * 3_600_000).toISOString());
71
+
72
+ // --- Network: private isolated subnets only (no IGW, no NAT) ---------
73
+ const vpc = new ec2.Vpc(this, 'Vpc', {
74
+ ipAddresses: ec2.IpAddresses.cidr('10.80.0.0/16'),
75
+ maxAzs: 2,
76
+ natGateways: 0,
77
+ subnetConfiguration: [{ name: 'private', subnetType: ec2.SubnetType.PRIVATE_ISOLATED, cidrMask: 24 }],
78
+ restrictDefaultSecurityGroup: true,
79
+ });
80
+ const privateSubnets = { subnetType: ec2.SubnetType.PRIVATE_ISOLATED };
81
+
82
+ const sg = (name: string, description: string) => new ec2.SecurityGroup(this, name, { vpc, description, allowAllOutbound: false });
83
+ const agentSg = sg('AgentSg', 'Pentest agent ENI: may reach the internal ALB on 80 only');
84
+ const albSg = sg('AlbSg', 'Internal ALB: accepts the pentest agent only');
85
+ const appSg = sg('AppSg', 'App tasks: accept the ALB only');
86
+ const endpointSg = sg('EndpointSg', 'VPC interface endpoints: accept the app tasks only');
87
+
88
+ agentSg.addEgressRule(albSg, ec2.Port.tcp(ALB_PORT), 'to the internal ALB');
89
+ albSg.addIngressRule(agentSg, ec2.Port.tcp(ALB_PORT), 'from the pentest agent');
90
+ appSg.addEgressRule(endpointSg, ec2.Port.tcp(443), 'to VPC interface endpoints');
91
+ endpointSg.addIngressRule(appSg, ec2.Port.tcp(443), 'from the app tasks');
92
+
93
+ vpc.addGatewayEndpoint('S3', { service: ec2.GatewayVpcEndpointAwsService.S3, subnets: [privateSubnets] });
94
+ const s3PrefixList = ec2.PrefixList.fromLookup(this, 'S3PrefixList', { prefixListName: `com.amazonaws.${this.region}.s3` });
95
+ appSg.addEgressRule(ec2.Peer.prefixList(s3PrefixList.prefixListId), ec2.Port.tcp(443), 'to S3 (ECR image layers)');
96
+
97
+ const appEnv = ctxJson<Record<string, string>>(this, 'env', {});
98
+ const appSecrets = ctxJson<Record<string, string>>(this, 'secrets', {});
99
+ const actorSecrets = ctxJson<string[]>(this, 'actorSecrets', []);
100
+ const actorLambdas = ctxJson<string[]>(this, 'actorLambdas', []);
101
+
102
+ const endpoints: [string, ec2.InterfaceVpcEndpointAwsService][] = [
103
+ ['EcrApi', ec2.InterfaceVpcEndpointAwsService.ECR],
104
+ ['EcrDkr', ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER],
105
+ ['Logs', ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS],
106
+ ];
107
+ // With no internet path, a task reads its secrets at start through this endpoint.
108
+ if (Object.keys(appSecrets).length) endpoints.push(['SecretsManager', ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER]);
109
+ for (const [cid, service] of endpoints) {
110
+ vpc.addInterfaceEndpoint(cid, { service, subnets: privateSubnets, securityGroups: [endpointSg], open: false, privateDnsEnabled: true });
111
+ }
112
+
113
+ // --- App: Fargate behind an internal ALB -----------------------------
114
+ // dockerfile: path relative to appDir (the build context); may be in a subfolder.
115
+ const dockerfile = ctxStr(this, 'dockerfile', 'Dockerfile');
116
+ const image = new ecrAssets.DockerImageAsset(this, 'Image', { directory: appDir, file: dockerfile, platform: ecrAssets.Platform.LINUX_AMD64 });
117
+ const appLogs = new logs.LogGroup(this, 'AppLogs', { retention: logs.RetentionDays.ONE_WEEK, removalPolicy: cdk.RemovalPolicy.DESTROY });
118
+ const cluster = new ecs.Cluster(this, 'Cluster', { vpc });
119
+ const task = new ecs.FargateTaskDefinition(this, 'Task', {
120
+ cpu: 256, memoryLimitMiB: 512,
121
+ runtimePlatform: { cpuArchitecture: ecs.CpuArchitecture.X86_64, operatingSystemFamily: ecs.OperatingSystemFamily.LINUX },
122
+ });
123
+ task.addContainer('app', {
124
+ image: ecs.ContainerImage.fromDockerImageAsset(image),
125
+ portMappings: [{ containerPort: port }],
126
+ environment: { ...appEnv, PORT: String(port) },
127
+ // Injected by ECS at task start; the execution role is granted read on exactly these secrets.
128
+ secrets: Object.fromEntries(Object.entries(appSecrets).map(([name, arn], i) => [name, ecs.Secret.fromSecretsManager(
129
+ isCompleteSecretArn(arn) ? secretsmanager.Secret.fromSecretCompleteArn(this, `AppSecret${i}`, arn) : secretsmanager.Secret.fromSecretPartialArn(this, `AppSecret${i}`, arn),
130
+ )])),
131
+ logging: ecs.LogDrivers.awsLogs({ logGroup: appLogs, streamPrefix: 'app' }),
132
+ });
133
+ const service = new ecs.FargateService(this, 'Service', {
134
+ cluster, taskDefinition: task, desiredCount: 1, minHealthyPercent: 100,
135
+ assignPublicIp: false, vpcSubnets: privateSubnets, securityGroups: [appSg], circuitBreaker: { rollback: true },
136
+ });
137
+
138
+ const alb = new elbv2.ApplicationLoadBalancer(this, 'Alb', {
139
+ vpc, internetFacing: false, vpcSubnets: privateSubnets, securityGroup: albSg, dropInvalidHeaderFields: true,
140
+ });
141
+ const listener = alb.addListener('Http', { port: ALB_PORT, protocol: elbv2.ApplicationProtocol.HTTP, open: false });
142
+ // Faster than the 5 x 30s default, so a new task turns healthy in ~20s; the
143
+ // command waits for a healthy target before starting the pentest.
144
+ const targetGroup = listener.addTargets('App', {
145
+ port, protocol: elbv2.ApplicationProtocol.HTTP, targets: [service],
146
+ healthCheck: { path: healthPath, interval: cdk.Duration.seconds(10), timeout: cdk.Duration.seconds(5), healthyThresholdCount: 2, unhealthyThresholdCount: 3 },
147
+ deregistrationDelay: cdk.Duration.seconds(10),
148
+ });
149
+
150
+ // --- Private hostname -------------------------------------------------
151
+ const zone = new route53.PrivateHostedZone(this, 'Zone', { zoneName, vpc });
152
+ new route53.ARecord(this, 'AppRecord', { zone, recordName: 'app', target: route53.RecordTarget.fromAlias(new targets.LoadBalancerTarget(alb)) });
153
+
154
+ // --- Source zip bucket and agent log group ---------------------------
155
+ const source = new s3.Bucket(this, 'Source', {
156
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, encryption: s3.BucketEncryption.S3_MANAGED,
157
+ enforceSSL: true, removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true,
158
+ });
159
+ const agentLogs = new logs.LogGroup(this, 'AgentLogs', { logGroupName, retention: logs.RetentionDays.ONE_WEEK, removalPolicy: cdk.RemovalPolicy.DESTROY });
160
+
161
+ // --- Pentest service role (scoped ENI permissions; spike-confirmed) ---
162
+ const subnetArns = vpc.isolatedSubnets.map((s) => this.formatArn({ service: 'ec2', resource: 'subnet', resourceName: s.subnetId }));
163
+ const agentSgArn = this.formatArn({ service: 'ec2', resource: 'security-group', resourceName: agentSg.securityGroupId });
164
+ const eniArn = this.formatArn({ service: 'ec2', resource: 'network-interface', resourceName: '*' });
165
+
166
+ const role = new iam.Role(this, 'ServiceRole', {
167
+ assumedBy: new iam.ServicePrincipal('securityagent.amazonaws.com', { conditions: { StringEquals: { 'aws:SourceAccount': this.account } } }),
168
+ description: 'prism-cli security pentest: Security Agent service role for one private VPC pentest',
169
+ });
170
+ role.addToPolicy(new iam.PolicyStatement({
171
+ sid: 'DescribeNetwork',
172
+ actions: ['ec2:DescribeDhcpOptions', 'ec2:DescribeNetworkInterfaces', 'ec2:DescribeNetworkInterfaceAttribute', 'ec2:DescribeSubnets', 'ec2:DescribeSecurityGroups', 'ec2:DescribeVpcs'],
173
+ resources: ['*'],
174
+ }));
175
+ role.addToPolicy(new iam.PolicyStatement({ sid: 'EniCreateScoped', actions: ['ec2:CreateNetworkInterface'], resources: [eniArn, agentSgArn, ...subnetArns] }));
176
+ role.addToPolicy(new iam.PolicyStatement({ sid: 'EniManageScoped', actions: ['ec2:ModifyNetworkInterfaceAttribute', 'ec2:DeleteNetworkInterface'], resources: [eniArn, agentSgArn], conditions: { StringEquals: { 'ec2:Vpc': vpc.vpcArn } } }));
177
+ role.addToPolicy(new iam.PolicyStatement({ sid: 'EniPermission', actions: ['ec2:CreateNetworkInterfacePermission'], resources: [eniArn], conditions: { ArnEquals: { 'ec2:Subnet': subnetArns } } }));
178
+ // Logs: create/describe the configured group (spike: PREFLIGHT fails CLIENT_ERROR without CreateLogGroup on the group ARN).
179
+ role.addToPolicy(new iam.PolicyStatement({ sid: 'LogsGroup', actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents', 'logs:DescribeLogStreams'], resources: [
180
+ // logGroupArn already ends in ':*', which does NOT match the bare group ARN
181
+ // CreateLogGroup is authorized against (the spike's second PREFLIGHT failure).
182
+ this.formatArn({ service: 'logs', resource: 'log-group', resourceName: logGroupName, arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME }),
183
+ agentLogs.logGroupArn,
184
+ ] }));
185
+ role.addToPolicy(new iam.PolicyStatement({ sid: 'LogsDescribe', actions: ['logs:DescribeLogGroups'], resources: ['*'] }));
186
+ source.grantRead(role);
187
+ // Test actors (.prism/pentest.json "actors"): the agent reads their credentials with this role.
188
+ actorSecrets.forEach((arn, i) => (isCompleteSecretArn(arn)
189
+ ? secretsmanager.Secret.fromSecretCompleteArn(this, `ActorSecret${i}`, arn)
190
+ : secretsmanager.Secret.fromSecretPartialArn(this, `ActorSecret${i}`, arn)).grantRead(role));
191
+ if (actorLambdas.length) role.addToPolicy(new iam.PolicyStatement({ sid: 'ActorCredentials', actions: ['lambda:InvokeFunction'], resources: actorLambdas }));
192
+
193
+ const out = (oid: string, value: string) => new cdk.CfnOutput(this, oid, { value });
194
+ out('VpcArn', vpc.vpcArn);
195
+ out('SubnetArns', cdk.Fn.join(',', subnetArns));
196
+ out('AgentSecurityGroupArn', agentSgArn);
197
+ out('AlbDnsName', alb.loadBalancerDnsName);
198
+ out('PrivateHost', `app.${zoneName}`);
199
+ out('ServiceRoleArn', role.roleArn);
200
+ out('SourceBucket', source.bucketName);
201
+ out('AgentLogGroup', agentLogs.logGroupName);
202
+ out('TargetGroupArn', targetGroup.targetGroupArn);
203
+ out('AppLogGroup', appLogs.logGroupName);
204
+ out('ExpiresAt', new Date(Date.now() + ttlHours * 3_600_000).toISOString());
205
+ }
206
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "prism-pentest-target-cdk",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "cdk": "cdk"
7
+ },
8
+ "dependencies": {
9
+ "aws-cdk-lib": "^2.265.0",
10
+ "constructs": "^10.4.2"
11
+ },
12
+ "devDependencies": {
13
+ "@types/node": "^20.17.0",
14
+ "aws-cdk": "^2.1000.0",
15
+ "ts-node": "^10.9.2",
16
+ "typescript": "~5.6.0"
17
+ }
18
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "commonjs",
5
+ "moduleResolution": "node",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "noEmit": true
10
+ },
11
+ "include": ["bin/**/*.ts", "lib/**/*.ts"]
12
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The fixed mapping behind `prism-cli aws recommend`: one entry per check id
3
+ * aws check can return. A test fails when a check id has no entry.
4
+ *
5
+ * effort: quick = one command or console toggle; medium = a setup step that
6
+ * takes some decisions; large = a project (migrating users, redesigning access).
7
+ */
8
+ export type Effort = 'quick' | 'medium' | 'large';
9
+ export interface Advice {
10
+ title: string;
11
+ why: string;
12
+ steps: string[];
13
+ /** The prism-cli command that fixes it, when there is one. */
14
+ command?: string;
15
+ doc: string;
16
+ effort: Effort;
17
+ /** IAM actions the check reads; shown when the check was INDETERMINATE. */
18
+ needs?: string[];
19
+ /** Replaces the generic "grant read access" item when INDETERMINATE means something else. */
20
+ indeterminate?: string;
21
+ /** Checks with the same key are one fix in aws recommend (default: the check id). */
22
+ key?: string;
23
+ /** The key of a fix this check can only be judged after (INDETERMINATE for that reason points at it). */
24
+ prerequisite?: string;
25
+ }
26
+ /** Title and wording for a key that several checks share. `first` names the fix when another check waits on it. */
27
+ export declare const GROUPS: Record<string, {
28
+ title: string;
29
+ why: string;
30
+ first: string;
31
+ }>;
32
+ export declare const ADVICE: Record<string, Advice>;
33
+ //# sourceMappingURL=advice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advice.d.ts","sourceRoot":"","sources":["../../../src/aws/advice.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yGAAyG;IACzG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,mHAAmH;AACnH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAMhF,CAAC;AAiBF,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0JzC,CAAC"}
@@ -0,0 +1,174 @@
1
+ /** Title and wording for a key that several checks share. `first` names the fix when another check waits on it. */
2
+ export const GROUPS = {
3
+ budgets: {
4
+ title: 'Create AWS Budgets: one for all spend, plus filters for Bedrock and AWS Marketplace',
5
+ why: 'Without budgets unexpected spend raises no alert, and Bedrock\'s third-party models bill under Marketplace, so a Bedrock-only filter misses them.',
6
+ first: 'Create the budgets',
7
+ },
8
+ };
9
+ const IAM = 'https://docs.aws.amazon.com/IAM/latest/UserGuide';
10
+ const COST = 'https://docs.aws.amazon.com/cost-management/latest/userguide';
11
+ const BEDROCK = 'https://docs.aws.amazon.com/bedrock/latest/userguide';
12
+ const GUIDE = 'https://github.com/aws-samples/sample-prism-d1-velocity/blob/main/USER_GUIDE.md';
13
+ const CREDENTIAL_REPORT = ['iam:GetCredentialReport (the report must exist: run aws iam generate-credential-report once, or prism-cli bedrock-protection scan-account)'];
14
+ const rootMfa = {
15
+ title: 'Add MFA to the root user', why: 'Root cannot be limited by SCPs or permission boundaries; without MFA a leaked root password is a full account takeover.',
16
+ steps: [
17
+ 'Sign in as the root user.', 'Security credentials > Assign MFA device; prefer a FIDO2 security key.',
18
+ 'In some managed or organization accounts the root user is controlled centrally; check with your account owner.',
19
+ ],
20
+ doc: `${IAM}/enable-mfa-for-root.html`, effort: 'quick', needs: ['iam:GetAccountSummary'],
21
+ };
22
+ export const ADVICE = {
23
+ // -- bedrock (bedrock-protection scan-account) ---------------------------------
24
+ 'bedrock.root-mfa': rootMfa,
25
+ 'bedrock.root-access-keys': {
26
+ title: 'Delete the root access keys', why: 'Root keys are long-lived and unconstrainable: the worst credential to leak.',
27
+ steps: ['Sign in as root > Security credentials > Access keys > Delete.', 'Move any automation that used them to an IAM role.'],
28
+ doc: `${IAM}/root-user-best-practices.html`, effort: 'quick', needs: ['iam:GetAccountSummary'],
29
+ },
30
+ 'bedrock.password-policy': {
31
+ title: 'Set an account password policy', why: 'Without one only the AWS defaults apply (8 characters, no reuse rules).',
32
+ steps: ['aws iam update-account-password-policy --minimum-password-length 14 --require-symbols --require-numbers --password-reuse-prevention 24', 'Better: move console users to IAM Identity Center.'],
33
+ doc: `${IAM}/id_credentials_passwords_account-policy.html`, effort: 'quick', needs: ['iam:GetAccountPasswordPolicy'],
34
+ },
35
+ 'bedrock.access-key-age': {
36
+ title: 'Rotate or remove long-lived access keys', why: 'Old static keys are what LLMjacking attackers steal and burn on Bedrock.',
37
+ steps: ['List the flagged keys (prism-cli bedrock-protection scan-account).', 'Replace each with a role (SSO, OIDC, instance profile), or rotate and delete the old key.'],
38
+ doc: `${IAM}/id_credentials_access-keys.html`, effort: 'medium', needs: CREDENTIAL_REPORT,
39
+ },
40
+ 'bedrock.console-user-no-mfa': {
41
+ title: 'Require MFA for console users', why: 'A console password without MFA falls to phishing or reuse.',
42
+ steps: ['Assign an MFA device to each flagged user, or move them to IAM Identity Center.'],
43
+ doc: `${IAM}/id_credentials_mfa_enable.html`, effort: 'medium', needs: CREDENTIAL_REPORT,
44
+ },
45
+ 'bedrock.unused-credentials': {
46
+ title: 'Remove unused credentials', why: 'Idle passwords and keys are attack surface nobody watches.',
47
+ steps: ['Deactivate the flagged passwords and keys, wait a week, then delete them.'],
48
+ doc: `${IAM}/id_credentials_finding-unused.html`, effort: 'quick', needs: CREDENTIAL_REPORT,
49
+ },
50
+ 'bedrock.user-admin-policy': {
51
+ title: 'Take AdministratorAccess off IAM users', why: 'Any access key of such a user is an unbounded credential.',
52
+ steps: ['Create an admin role gated on MFA (or an Identity Center permission set).', 'Detach AdministratorAccess from the users.'],
53
+ doc: `${IAM}/best-practices.html`, effort: 'large', needs: ['iam:ListUsers', 'iam:ListAttachedUserPolicies'],
54
+ },
55
+ 'bedrock.bedrock-budget': {
56
+ title: 'Add a budget that covers Bedrock', why: 'Runaway inference from a stolen key has no ceiling and raises no alert.',
57
+ steps: ['Billing > Budgets > Create a monthly COST budget filtered on Service contains "Bedrock".', 'Alert at 50/80/100% to an SNS topic.'],
58
+ doc: `${COST}/budgets-create.html`, effort: 'quick', needs: ['budgets:ViewBudget'], key: 'budgets',
59
+ },
60
+ 'bedrock.marketplace-budget': {
61
+ title: 'Add a budget that covers AWS Marketplace (Bedrock Edition models)', why: 'Third-party models bill under Marketplace, so a Bedrock-only budget misses them.',
62
+ steps: ['Create a second COST budget filtered on Service = AWS Marketplace, or one Cost Category covering both.'],
63
+ doc: `${COST}/budgets-create.html`, effort: 'quick', needs: ['budgets:ViewBudget'], key: 'budgets',
64
+ },
65
+ 'bedrock.budget-alerting': {
66
+ title: 'Make the Bedrock budgets notify someone', why: 'A budget with no subscriber records the overspend without telling anyone.',
67
+ steps: ['Add 50/80/100% notification thresholds with an SNS topic (or email) subscriber to each covering budget.'],
68
+ doc: `${COST}/budgets-sns-policy.html`, effort: 'quick', needs: ['budgets:ViewBudget'], prerequisite: 'budgets',
69
+ },
70
+ 'bedrock.cost-explorer-enabled': {
71
+ title: 'Enable Cost Explorer', why: 'Anomaly detection and cost checks need it, and it stays off until someone turns it on.',
72
+ steps: ['Billing > Cost Explorer > Enable (data appears within 24 hours).'],
73
+ doc: `${COST}/ce-enable.html`, effort: 'quick', needs: ['ce:GetAnomalyMonitors'],
74
+ },
75
+ 'bedrock.anomaly-monitor': {
76
+ title: 'Add a cost anomaly monitor with an alert subscription', why: 'It catches spend spikes a fixed budget threshold misses.',
77
+ steps: ['Billing > Cost Anomaly Detection > Create an AWS services monitor.', 'Add an alert subscription (SNS or email).'],
78
+ doc: `${COST}/getting-started-ad.html`, effort: 'quick', needs: ['ce:GetAnomalyMonitors', 'ce:GetAnomalySubscriptions'],
79
+ },
80
+ 'bedrock.bedrock-invocation-alarm': {
81
+ title: 'Alarm on Bedrock invocation volume', why: 'Cost data lags up to a day; the AWS/Bedrock metrics are the only fast signal.',
82
+ steps: ['Create CloudWatch alarms on AWS/Bedrock Invocations and InputTokenCount above normal peak.'],
83
+ doc: `${BEDROCK}/monitoring.html`, effort: 'medium', needs: ['cloudwatch:DescribeAlarms'],
84
+ },
85
+ 'bedrock.guardduty-ai-protection': {
86
+ title: 'Enable GuardDuty AI Protection', why: 'It detects cost-harvesting patterns against Bedrock.',
87
+ steps: ['Enable GuardDuty in the region if needed, then the AI_PROTECTION feature on the detector (org-wide from the delegated administrator if you can).'],
88
+ doc: 'https://docs.aws.amazon.com/guardduty/latest/ug/what-is-guardduty.html', effort: 'quick', needs: ['guardduty:ListDetectors', 'guardduty:GetDetector'],
89
+ },
90
+ 'bedrock.provisioned-throughput': {
91
+ title: 'Review Provisioned Throughput commitments', why: 'A commitment bills whether or not it is used, and is a target for misuse.',
92
+ steps: ['Check each commitment is expected and owned; delete the ones nobody uses when their term allows.'],
93
+ doc: `${BEDROCK}/prov-throughput.html`, effort: 'medium', needs: ['bedrock:ListProvisionedModelThroughputs'],
94
+ },
95
+ 'bedrock.model-invocation-logging': {
96
+ title: 'Turn on Bedrock model invocation logging', why: 'Without it you can see spend rose but not who or what caused it.',
97
+ steps: ['Bedrock console > Settings > Model invocation logging > CloudWatch Logs or S3.', 'Treat the destination as sensitive: it holds prompts and completions.'],
98
+ doc: `${BEDROCK}/model-invocation-logging.html`, effort: 'quick', needs: ['bedrock:GetModelInvocationLoggingConfiguration'],
99
+ },
100
+ // -- prism-setup -------------------------------------------------------------
101
+ 'prism-setup.metrics-pipeline': {
102
+ title: 'Deploy the PRISM metrics pipeline', why: 'Without it CI and codeburn have nowhere to send PRISM metrics.',
103
+ steps: ['From the repo: cd infra && npm ci && npx cdk deploy PrismD1MetricsPipeline (see the workshop setup guide).'],
104
+ doc: `${GUIDE}`, effort: 'medium', needs: ['cloudformation:DescribeStacks'],
105
+ },
106
+ 'prism-setup.security-agent-stack': {
107
+ title: 'Set up AWS Security Agent', why: 'The CI eval gate and the security commands need its stack.',
108
+ steps: ['Run the command below; it shows a diff and asks before any change.'], command: 'prism-cli enable security',
109
+ doc: `${GUIDE}#security-agent-setup-enable-security`, effort: 'quick', needs: ['cloudformation:DescribeStacks', 'cloudformation:GetTemplate'],
110
+ },
111
+ 'prism-setup.security-agent-ssm': {
112
+ title: 'Restore the Security Agent SSM parameters', why: 'The CI gate and security commands find the agent space and scan bucket through /prism/continuum/*.',
113
+ steps: ['Run the command below (the stack owns these parameters; do not edit them by hand).'], command: 'prism-cli enable security',
114
+ doc: `${GUIDE}#security-agent-setup-enable-security`, effort: 'quick', needs: ['ssm:GetParameter', 'securityagent:ListAgentSpaces'],
115
+ },
116
+ 'prism-setup.scan-bucket-listed': {
117
+ title: 'List the scan bucket on the Security Agent space', why: 'security threat-model fails when the agent space does not list the scan bucket.',
118
+ steps: ['Run the command below to update the stack.'], command: 'prism-cli enable security',
119
+ doc: `${GUIDE}#security-agent-setup-enable-security`, effort: 'quick', needs: ['securityagent:BatchGetAgentSpaces'],
120
+ },
121
+ 'prism-setup.ci-oidc-role': {
122
+ title: 'Create the CI OIDC provider and role', why: 'CI should publish PRISM metrics with short-lived OIDC credentials, not stored keys.',
123
+ steps: ['Run the command below (or bootstrapper setup-gitlab-oidc for GitLab).', 'Set PRISM_METRICS_ROLE_ARN in the CI settings to the role it prints.'],
124
+ command: 'prism-cli bootstrapper setup-github-oidc', doc: GUIDE, effort: 'quick', needs: ['iam:ListOpenIDConnectProviders', 'iam:ListRoles'],
125
+ },
126
+ 'prism-setup.codeburn-sync': {
127
+ title: 'Connect codeburn to the PRISM collector', why: 'This machine sends no AI usage telemetry to PRISM until codeburn sync is set up.',
128
+ steps: ['Run the command below; it installs codeburn if missing and schedules the sync.'], command: 'prism-cli enable codeburn',
129
+ doc: GUIDE, effort: 'quick', indeterminate: 'The codeburn sync config (~/.config/codeburn/sync.json) could not be read; check the file or re-run prism-cli enable codeburn.',
130
+ },
131
+ // -- baseline ----------------------------------------------------------------
132
+ 'baseline.cloudtrail-multiregion': {
133
+ title: 'Log API activity in every region with a multi-region trail', why: 'Without it activity in other regions leaves no record for an investigation.',
134
+ steps: ['aws cloudtrail create-trail --name prism-audit --s3-bucket-name <bucket> --is-multi-region-trail', 'aws cloudtrail start-logging --name prism-audit', 'In an organization, prefer one organization trail from the management account.'],
135
+ doc: 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-create-and-update-a-trail.html', effort: 'medium', needs: ['cloudtrail:DescribeTrails', 'cloudtrail:GetTrailStatus'],
136
+ },
137
+ 'baseline.guardduty': {
138
+ title: 'Enable GuardDuty', why: 'It is the managed threat detection for compromised credentials and instances.',
139
+ steps: ['aws guardduty create-detector --enable --region <region>', 'In an organization, enable it from a delegated administrator with auto-enable.'],
140
+ doc: 'https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html', effort: 'quick', needs: ['guardduty:ListDetectors', 'guardduty:GetDetector'],
141
+ },
142
+ 'baseline.securityhub': {
143
+ title: 'Enable Security Hub', why: 'It runs the AWS Foundational Security Best Practices checks continuously and collects findings in one place.',
144
+ steps: ['Security Hub console > Enable, with the AWS Foundational Security Best Practices standard.'],
145
+ doc: 'https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-settingup.html', effort: 'quick', needs: ['securityhub:DescribeHub'],
146
+ },
147
+ 'baseline.access-analyzer': {
148
+ title: 'Create an IAM Access Analyzer', why: 'It flags buckets, roles and keys shared outside the account.',
149
+ steps: ['aws accessanalyzer create-analyzer --analyzer-name prism --type ACCOUNT --region <region>'],
150
+ doc: `${IAM}/access-analyzer-getting-started.html`, effort: 'quick', needs: ['access-analyzer:ListAnalyzers'],
151
+ },
152
+ 'baseline.budget': {
153
+ title: 'Create an AWS Budget', why: 'Without a budget, unexpected spend raises no alert.',
154
+ steps: ['Billing > Budgets > Create a monthly cost budget for all services with 80% and 100% alerts.'],
155
+ doc: `${COST}/budgets-create.html`, effort: 'quick', needs: ['budgets:ViewBudget'], key: 'budgets',
156
+ },
157
+ 'baseline.s3-account-bpa': {
158
+ title: 'Turn on S3 Block Public Access for the account', why: 'One misconfigured bucket policy or ACL is otherwise enough to publish data.',
159
+ steps: ['aws s3control put-public-access-block --account-id <account> --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true', 'First check no bucket needs public access on purpose.'],
160
+ doc: 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html', effort: 'quick', needs: ['s3:GetAccountPublicAccessBlock'],
161
+ },
162
+ 'baseline.ebs-default-encryption': {
163
+ title: 'Encrypt new EBS volumes by default', why: 'Unencrypted volumes and snapshots can expose data when shared or copied.',
164
+ steps: ['aws ec2 enable-ebs-encryption-by-default --region <region> (applies to new volumes only).'],
165
+ doc: 'https://docs.aws.amazon.com/ebs/latest/userguide/ebs-encryption.html', effort: 'quick', needs: ['ec2:GetEbsEncryptionByDefault'],
166
+ },
167
+ // -- startup-advisor ---------------------------------------------------------
168
+ 'startup-advisor.not-integrated': {
169
+ title: 'Startup Advisor checks', why: 'Planned: PRISM will reuse Startup Advisor\'s account checks once how to consume them, and the license, are settled.',
170
+ steps: ['Nothing to do yet.'], doc: 'https://github.com/aws-samples/sample-prism-d1-velocity/blob/main/docs/PRISM-CLI-STATUS.md', effort: 'quick',
171
+ indeterminate: 'Not integrated yet; nothing to grant or fix.',
172
+ },
173
+ };
174
+ //# sourceMappingURL=advice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advice.js","sourceRoot":"","sources":["../../../src/aws/advice.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * `prism-cli aws check`: read-only account checks on the audit framework
3
+ * (utils/audit.ts), in pluggable sections. A section is a name, a heading,
4
+ * the check ids it can return, and a run function; SECTIONS is the registry.
5
+ *
6
+ * Every AWS call here is a read. INDETERMINATE (a denied or failed read) is
7
+ * never counted as a pass.
8
+ */
9
+ import { type AwsTarget } from '../utils/aws.js';
10
+ import { type Finding, type Severity } from '../utils/audit.js';
11
+ import { type Ctx, type Deps, type Resolved } from '../security/setup.js';
12
+ export interface CheckContext {
13
+ target: AwsTarget;
14
+ account: string;
15
+ region: string;
16
+ home: string;
17
+ /** A read-only enable-security context, for the Security Agent rows. */
18
+ security: Ctx;
19
+ }
20
+ export interface CheckSection {
21
+ name: string;
22
+ heading: string;
23
+ /** Every check id run() can return (without the section prefix). */
24
+ ids: readonly string[];
25
+ run(c: CheckContext): Finding[];
26
+ }
27
+ /** `<section>.<id>`: one id space across sections (a check appears in one section only). */
28
+ export declare const checkId: (section: string, id: string) => string;
29
+ export declare const bedrockSection: CheckSection;
30
+ export declare function metricsPipeline(c: CheckContext): Finding;
31
+ /** Maps the enable security --status rows to findings. A row that never appeared (the report stopped) is INDETERMINATE. */
32
+ export declare function securityAgent(c: CheckContext): Finding[];
33
+ export declare function ciOidcRole(c: CheckContext): Finding;
34
+ /** Local only: the endpoint codeburn syncs to (~/.config/codeburn/sync.json). No AWS call. */
35
+ export declare function codeburnSync(c: CheckContext): Finding;
36
+ export declare const prismSetupSection: CheckSection;
37
+ export declare function cloudTrail(c: CheckContext): Finding;
38
+ export declare function guardDuty(c: CheckContext): Finding;
39
+ export declare function securityHub(c: CheckContext): Finding;
40
+ export declare function accessAnalyzer(c: CheckContext): Finding;
41
+ export declare function budget(c: CheckContext): Finding;
42
+ export declare function s3PublicAccess(c: CheckContext): Finding;
43
+ export declare function ebsEncryption(c: CheckContext): Finding;
44
+ export declare const baselineSection: CheckSection;
45
+ export declare const startupAdvisorSection: CheckSection;
46
+ export declare const SECTIONS: CheckSection[];
47
+ /** Every full check id any section can return. */
48
+ export declare const ALL_CHECK_IDS: string[];
49
+ /** The sections named by --section (all when none), or an error naming the valid ones. */
50
+ export declare function selectSections(names: string[] | undefined): CheckSection[] | {
51
+ error: string;
52
+ };
53
+ export interface SectionCounts {
54
+ pass: number;
55
+ fail: number;
56
+ indeterminate: number;
57
+ }
58
+ export declare function countFindings(findings: Finding[]): SectionCounts;
59
+ export declare function failBySeverity(findings: Finding[]): Record<Severity, number>;
60
+ /** FAIL findings at or above `failOn` (none when failOn is null). */
61
+ export declare function breaching(findings: Finding[], failOn: Severity | null): Finding[];
62
+ /** A read-only enable-security context for collectSecurityStatus. Repo rows are skipped (git reports no repo). */
63
+ export declare function securityContext(opts: Resolved, aws: Deps['aws'], env: NodeJS.ProcessEnv, awsVersion: () => string | null, log: (l?: string) => void): Ctx;
64
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/aws/check.ts"],"names":[],"mappings":"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"}