Skip to content

Commit

Permalink
Feat/default ecs policy (#169)
Browse files Browse the repository at this point in the history
* (chore): Update publish global

* (feat): Add func createInstancePolicy for handle default policy

* feat(nx-aws-cdk): remove tag comment

* feat(nx-aws-cdk): update minimal policy

* feat(nx-aws-cdk): remove get secret resource

* feat(nx-aws-cdk): update ssm policy

* fix(nx-aws-cdk): update logic check exsiting role or not and create new one.

* feat(nx-aws-cdk): format string resource in aws-cdk-stack

* feat(nx-aws-cdk): clean code and format code spacing

* feat(nx-aws-cdk): add ebs Encrypted and KmsKeyId option

* fix(nx-aws-cdk): fix user-data string format

* chore(nx-aws-cdk): update aws-cdk-stack version

* fix(nx-aws-cdk): remove CloudWatch logs in minimal policy

* feat(nx-aws-cdk): reduce minimal policy

* fix(nx-aws-cdk): fix role checking method

* feat(nx-aws-cdk): add existingRole for crete new role or get existing role

* feat(nx-aws-cdk): add existingRole flag for handle get exist role or create new ones.
  • Loading branch information
NarongOk authored Nov 20, 2024
1 parent 10e5fb8 commit dbc4f30
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 23 deletions.
2 changes: 1 addition & 1 deletion libs/aws-cdk-stack/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@flowaccount/aws-cdk-stack",
"version": "2.0.2",
"version": "2.0.3",
"dependencies": {
"constructs": "^10.3.0",
"aws-cdk": "^2.143.1",
Expand Down
83 changes: 78 additions & 5 deletions libs/aws-cdk-stack/src/lib/stacks/aws-ecs-cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import { ECSCapacityProvider } from './ecs-capacity-provider';
import { ManagedPolicyStack } from './managed-policy-stack';
import { RoleStack } from './role-stack';
import { VpcStack } from './vpc';
import { IECSStackEnvironmentConfig } from '../types';
import {
IECSStackEnvironmentConfig,
PolicyModel,
PolicyStackProperties,
PolicyStatementModel,
} from '../types';

/**
* This class is used to create an ECS cluster stack by specifying the VPC and Subnets
Expand Down Expand Up @@ -63,14 +68,18 @@ export const createStack = (configuration: IECSStackEnvironmentConfig) => {
{
name: configuration.ecs.instanceRole.name,
assumedBy: configuration.ecs.instanceRole.assumedBy,
existingRole: configuration.ecs.instanceRole.existingRole ?? false,
}
).output.role;

// instance policy
new ManagedPolicyStack(_app, `${configuration.ecs.instancePolicy.name}`, {
...configuration.ecs.instancePolicy,
roles: [_instanceRole],
}).output.policy;
createInstancePolicy(
_app,
configuration.ecs.instancePolicy.name,
configuration.ecs.instancePolicy,
[_instanceRole],
configuration.stage
);

// task execution role and policy
const _taskExecutionRole: IRole = new RoleStack(
Expand Down Expand Up @@ -175,3 +184,67 @@ export const createStack = (configuration: IECSStackEnvironmentConfig) => {
// })
});
};

const createInstancePolicy = (
app: App,
instancePolicyName: string,
extendedPolicy: PolicyModel,
instanceRoles?: IRole[],
stage?: string
) => {
const ec2Policy: PolicyStatementModel = {
actions: [
'ec2:DescribeInstances',
'ec2:DescribeRegions',
'ec2:DescribeSecurityGroups',
'ec2:DescribeSubnets',
'ec2:DescribeVpcs',
],
resources: ['*'],
};

const ssmPolicy: PolicyStatementModel = {
actions: [
'ssm:DescribeAssociation',
'ssm:GetDeployablePatchSnapshotForInstance',
'ssm:GetDocument',
'ssm:DescribeDocument',
'ssm:GetManifest',
'ssm:GetParameter',
'ssm:GetParameters',
'ssm:ListAssociations',
'ssm:ListInstanceAssociations',
'ssm:PutInventory',
'ssm:PutComplianceItems',
'ssm:PutConfigurePackageResult',
'ssm:UpdateAssociationStatus',
'ssm:UpdateInstanceAssociationStatus',
'ssm:UpdateInstanceInformation',
`ssmmessages:CreateControlChannel`,
`ssmmessages:CreateDataChannel`,
`ssmmessages:OpenControlChannel`,
`ssmmessages:OpenDataChannel`,
`ec2messages:AcknowledgeMessage`,
`ec2messages:DeleteMessage`,
`ec2messages:FailMessage`,
`ec2messages:GetEndpoint`,
`ec2messages:GetMessages`,
`ec2messages:SendReply`,
],
resources: ['*'],
};

const statements: PolicyStatementModel[] = [ec2Policy, ssmPolicy];
statements.push(...extendedPolicy.statements);

const instancePolicyProps: PolicyStackProperties = {
statements: statements,
name: extendedPolicy.name
? extendedPolicy.name
: `default-${stage}-cluster-policy`,
roles: instanceRoles,
};

return new ManagedPolicyStack(app, instancePolicyName, instancePolicyProps)
.output.policy;
};
23 changes: 14 additions & 9 deletions libs/aws-cdk-stack/src/lib/stacks/ecs-autoscaling-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
CfnLaunchTemplate,
SecurityGroup,
SubnetType,
AmazonLinuxImage,
} from 'aws-cdk-lib/aws-ec2';
import { CfnInstanceProfile, IRole } from 'aws-cdk-lib/aws-iam';
import {
Expand Down Expand Up @@ -53,6 +52,7 @@ EOF
amazon-linux-extras disable docker && amazon-linux-extras install -y ecs && systemctl enable --now --no-block ecs
docker plugin install rexray/ebs EBS_REGION=${stackProps.env.region} --grant-all-permissions
`;

if (stackProps.s3MountConfig) {
_userData = `
#!/bin/bash
Expand Down Expand Up @@ -85,6 +85,7 @@ sudo s3cmd sync s3://${stackProps.s3MountConfig.bucketName} ${stackProps.s3Mount
</powershell>
`;
}

const _securityGroup = new SecurityGroup(
this,
stackProps.asgModel.asg.instanceSecurityGroup.name,
Expand All @@ -94,11 +95,13 @@ sudo s3cmd sync s3://${stackProps.s3MountConfig.bucketName} ${stackProps.s3Mount
securityGroupName: stackProps.asgModel.asg.instanceSecurityGroup.name,
}
);

stackProps.asgModel.asg.instanceSecurityGroup.inboudRule.forEach(
(_rule) => {
_securityGroup.addIngressRule(_rule.peer, _rule.connection);
}
);

const _instanceProfile = new CfnInstanceProfile(
this,
stackProps.asgModel.asg.instanceProfileName,
Expand All @@ -107,6 +110,7 @@ sudo s3cmd sync s3://${stackProps.s3MountConfig.bucketName} ${stackProps.s3Mount
instanceProfileName: stackProps.asgModel.asg.instanceProfileName,
}
);

const _launchTemplate: CfnLaunchTemplate = new CfnLaunchTemplate(
this,
stackProps.asgModel.launchTemplate.name,
Expand All @@ -129,6 +133,8 @@ sudo s3cmd sync s3://${stackProps.s3MountConfig.bucketName} ${stackProps.s3Mount
volumeType: stackProps.asgModel.launchTemplate.volumeType,
volumeSize: stackProps.asgModel.launchTemplate.volumeSize,
deleteOnTermination: true,
encrypted: stackProps.asgModel.launchTemplate.encrypted,
kmsKeyId: stackProps.asgModel.launchTemplate.kmsKeyId,
},
deviceName: '/dev/xvda',
},
Expand Down Expand Up @@ -171,7 +177,7 @@ sudo s3cmd sync s3://${stackProps.s3MountConfig.bucketName} ${stackProps.s3Mount
SpotAllocationStrategy: 'capacity-optimized',
},
});
asgGroup.addDependsOn(_launchTemplate);
asgGroup.addDependency(_launchTemplate);
this._autoScalingGroup = asgGroup;
// });

Expand All @@ -180,12 +186,10 @@ sudo s3cmd sync s3://${stackProps.s3MountConfig.bucketName} ${stackProps.s3Mount
});
// ECS Cluster and Auto Scaling Group
// let protection: string = stackProps.asgModel.asg.protectionFromScaleIn==true? 'ENABLED': 'DISABLED'
let protection: string;
if (stackProps.asgModel.asg.protectionFromScaleIn) {
protection = 'ENABLED';
} else {
protection = 'DISABLED';
}
const protection: string = stackProps.asgModel.asg.protectionFromScaleIn
? 'ENABLED'
: 'DISABLED';

const myCapacityProvider = new CfnCapacityProvider(
this,
`${asgGroup.autoScalingGroupName}`,
Expand All @@ -201,6 +205,7 @@ sudo s3cmd sync s3://${stackProps.s3MountConfig.bucketName} ${stackProps.s3Mount
name: `${asgGroup.autoScalingGroupName}`,
}
);
myCapacityProvider.addDependsOn(asgGroup);

myCapacityProvider.addDependency(asgGroup);
}
}
15 changes: 12 additions & 3 deletions libs/aws-cdk-stack/src/lib/stacks/managed-policy-stack.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { ManagedPolicy, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { Stack } from 'aws-cdk-lib/core'; import { Construct } from 'constructs';
import { ManagedPolicy, PolicyStatement, IRole } from 'aws-cdk-lib/aws-iam';
import { Stack } from 'aws-cdk-lib/core';
import { Construct } from 'constructs';
import { logger } from '@nx/devkit';
import { PolicyStackProperties } from '../types';

export class ManagedPolicyStack extends Stack {
public readonly output: {
policy: ManagedPolicy;
};

constructor(scope: Construct, id: string, _props: PolicyStackProperties) {
super(scope, id, _props);

Expand All @@ -22,6 +24,7 @@ export class ManagedPolicyStack extends Stack {
}
});
}

const _policyStatements: PolicyStatement[] = [];
_props.statements?.forEach((statement) => {
const policyStatement = new PolicyStatement();
Expand All @@ -33,12 +36,18 @@ export class ManagedPolicyStack extends Stack {
});
_policyStatements.push(policyStatement);
});

logger.debug(`creating policy:${_props.name}`);
const _policy = new ManagedPolicy(this, _props.name, {
managedPolicyName: _props.name,
statements: _policyStatements,
roles: _props.roles,
});

logger.debug(`attach policy to roles`);
_props.roles?.forEach((role: IRole) => {
_policy.attachToRole(role);
});

this.output = { policy: _policy };
}
}
14 changes: 10 additions & 4 deletions libs/aws-cdk-stack/src/lib/stacks/role-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ export class RoleStack extends Stack {
super(scope, id, _props);

if (_props.existingRole) {
const role = Role.fromRoleName(this, `${_props.name}`, _props.name, {});
this.output = { role: role };
const existingRole: IRole = Role.fromRoleName(
this,
_props.name,
_props.name,
{}
);
existingRole;
this.output = { role: existingRole };
} else {
logger.debug(`creating role -- ${_props.name}`);
const role = new Role(this, `${_props.name}`, {
const newRole = new Role(this, `${_props.name}`, {
roleName: _props.name,
assumedBy: new CompositePrincipal(..._props.assumedBy),
});
this.output = { role: role };
this.output = { role: newRole };
}
}
}
10 changes: 10 additions & 0 deletions libs/aws-cdk-stack/src/lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,9 @@ export abstract class ECSStackEnvironmentConfig {
export class RoleModel {
name: string;
assumedBy: PrincipalBase[];
existingRole?: boolean;
}

export class AutoScalingGroupModel {
launchTemplate: {
name: string;
Expand All @@ -351,6 +353,8 @@ export class AutoScalingGroupModel {
version: number | string;
volumeType: string;
volumeSize: number;
encrypted?: boolean;
kmsKeyId?: string;
};
asg: {
name: string;
Expand All @@ -365,24 +369,29 @@ export class AutoScalingGroupModel {
instanceSecurityGroup: SecurityGroupsModel;
};
}

class SecurityGroupsInboudRuleModel {
peer: IPeer;
connection: Port;
}

class SecurityGroupsModel {
name: string;
inboudRule: SecurityGroupsInboudRuleModel[];
}

export class PolicyStatementModel {
actions: string[];
resources: string[];
conditions?: Conditions;
}

export class PolicyModel {
statements?: PolicyStatementModel[];
statement?: PolicyStatementModel;
name: string;
}

export class ECSModel {
instancePolicy: PolicyModel;
instanceRole: RoleModel;
Expand Down Expand Up @@ -478,6 +487,7 @@ export class TagModel {
key: string;
value: string;
}

export class S3MountConfig {
bucketName: string;
localPath: string;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"help": "nx help",
"workspace-generator": "nx workspace-generator",
"e2e-registry": "yarn verdaccio --config ./tools/scripts/local-registry/config.yml --listen 4872",
"publish-global": "yarn nx build $1 && cd dist/libs/$1 && npm publish",
"publish-global": "publish() { yarn nx build $1 && cd dist/libs/$1 && npm publish; }; publish ",
"publish-beta": "ts-node tools/scripts/publish-beta",
"publish-local": "cp .npmrc.local .npmrc && run-p \"rimraf tmp\" e2e-registry \"ts-node ./tools/scripts/publish-all 99.99.99 local\"",
"semantic-release": "semantic-release",
Expand Down

0 comments on commit dbc4f30

Please sign in to comment.