open-swe/infra/lib/open-swe-stack.ts
Adam Moussa 92fd886076
feat(infra): add /infra CDK scaffold + per-env OIDC/instance IAM role defs (#6)
PR#1 of the AWS migration. CDK TypeScript app under /infra: stacks open-swe-iam
(four per-env GitHub-OIDC deploy roles) + open-swe-dev/-prod (per-env EC2 instance
role + AMI cache). aws-cdk-lib pinned exact 2.260.0; kebab naming Aspect + 15 tests.

IAM is synth-only (NOT deployed). Cleared the Phase-1 security gates:
- T4 GPT-4.1 IAM cross-review (StringEquals trust; cdk-hnb659fds-* wildcard kept as
  org convention; AWS-RunShellScript timeboxed to T19).
- T5 /sh-security-review: deploy roles split PER-ENV with env-scoped OIDC trust
  (dev=branch ref+tag dev, prod=environment:prod+tag prod) so a dev token cannot
  reach prod; re-verified block:false.
2026-06-26 15:06:30 -04:00

58 lines
2.2 KiB
TypeScript

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import { EnvName, prefix } from "./config";
import { InstanceRole } from "./constructs/instance-role";
import {
AL2023_ARM64_SSM_CONTEXT_KEY,
cachedArm64AmazonLinux2023,
} from "./constructs/ami-cache";
export interface OpenSweStackProps extends cdk.StackProps {
/** open-swe environment — drives the `open-swe-<env>-*` resource naming. */
readonly envName: EnvName;
}
/**
* Per-env open-swe stack (`open-swe-dev` / `open-swe-prod`). Resource names are
* prefixed `open-swe-<env>-*`.
*
* T3 scope: the per-env EC2 instance role + the wired-but-not-yet-instantiated
* AMI cache helper. The EC2 instance, ALB target groups, listener rules, SG,
* Route53 and NAT come at T12 — this stack is the synth-able shell they plug
* into.
*/
export class OpenSweStack extends cdk.Stack {
public readonly instanceRole: InstanceRole;
constructor(scope: Construct, id: string, props: OpenSweStackProps) {
super(scope, id, props);
const envName = props.envName;
const p = prefix(envName);
cdk.Tags.of(this).add("project", "open-swe");
cdk.Tags.of(this).add("env", envName);
cdk.Tags.of(this).add("ManagedBy", "cdk");
// Per-env least-privilege EC2 instance role (open-swe-<env>-instance-role).
this.instanceRole = new InstanceRole(this, "Instance", envName);
// AMI cache discipline (see lib/constructs/ami-cache.ts). T3 is synth-only:
// resolve + surface the pinned AMI id ONLY when it is already cached in
// cdk.context.json, so synth never makes a live SSM call. T12 consumes
// `cachedArm64AmazonLinux2023()` for the actual ec2.Instance.
if (this.node.tryGetContext(AL2023_ARM64_SSM_CONTEXT_KEY) !== undefined) {
const amiId = cachedArm64AmazonLinux2023().getImage(this).imageId;
new cdk.CfnOutput(this, "PinnedAmiId", {
value: amiId,
description:
"Cached AL2023 ARM64 AMI id (pinned in cdk.context.json; consumed by the T12 EC2 instance).",
});
}
new cdk.CfnOutput(this, "InstanceRoleArn", {
value: this.instanceRole.role.roleArn,
description: `${p} EC2 instance role ARN.`,
});
}
}