import * as cdk from "aws-cdk-lib"; import * as identitystore from "aws-cdk-lib/aws-identitystore"; import * as sso from "aws-cdk-lib/aws-sso"; import { Construct } from "constructs"; const IDENTITY_CENTER_INSTANCE_ARN = "arn:aws:sso:::instance/ssoins-722321f42ca610e4"; const IDENTITY_STORE_ID = "d-9067ec8e26"; const VIEW_ONLY_ACCESS_ARN = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"; /** * Blocks secret, object, and item reads if a broader managed policy is * attached later. ViewOnlyAccess is the allow. ReadOnlyAccess is not used. */ const DATA_PLANE_DENY = { Version: "2012-10-17", Statement: [ { Sid: "DenyDataPlaneReads", Effect: "Deny", Action: [ "secretsmanager:GetSecretValue", "secretsmanager:BatchGetSecretValue", "ssm:GetParameter", "ssm:GetParameters", "ssm:GetParametersByPath", "kms:Decrypt", "s3:GetObject", "dynamodb:GetItem", "dynamodb:BatchGetItem", "dynamodb:Query", "dynamodb:Scan", ], Resource: "*", }, ], }; export interface EngineeringAccessStackProps extends cdk.StackProps { devAccountId: string; prodAccountId: string; } /** * Identity Center group and view-only permission sets for the engineering * team (PLAT-235). * * Assigned to seahaven-dev and seahaven-prod only. The group has no members. * People are added after the roster exists, outside this stack. This is not * an SCP exemption and cannot assume OrganizationAccountAccessRole. * * A later SCIM sync of engineering@seahaven.com must adopt this group. A * second group with display name engineering will collide. */ export class EngineeringAccessStack extends cdk.Stack { constructor(scope: Construct, id: string, props: EngineeringAccessStackProps) { super(scope, id, props); const group = new identitystore.CfnGroup(this, "EngineeringGroup", { identityStoreId: IDENTITY_STORE_ID, displayName: "engineering", description: "Engineering team. View-only in seahaven-dev and seahaven-prod. No members until the roster exists.", }); const devPermissionSet = this.permissionSet( "EngineeringDevPermissionSet", "EngineeringDev", "View-only in seahaven-dev. No secret, object, or item reads.", ); const prodPermissionSet = this.permissionSet( "EngineeringProdPermissionSet", "EngineeringProd", "View-only in seahaven-prod. No secret, object, or item reads.", ); this.assignment( "EngineeringDevAssignment", devPermissionSet, group, props.devAccountId, ); this.assignment( "EngineeringProdAssignment", prodPermissionSet, group, props.prodAccountId, ); } private permissionSet( id: string, name: string, description: string, ): sso.CfnPermissionSet { return new sso.CfnPermissionSet(this, id, { instanceArn: IDENTITY_CENTER_INSTANCE_ARN, name, description, sessionDuration: "PT8H", managedPolicies: [VIEW_ONLY_ACCESS_ARN], inlinePolicy: DATA_PLANE_DENY, }); } private assignment( id: string, permissionSet: sso.CfnPermissionSet, group: identitystore.CfnGroup, targetId: string, ): void { new sso.CfnAssignment(this, id, { instanceArn: IDENTITY_CENTER_INSTANCE_ARN, permissionSetArn: permissionSet.attrPermissionSetArn, principalId: group.attrGroupId, principalType: "GROUP", targetId, targetType: "AWS_ACCOUNT", }); } }