Skip to content

Commit

Permalink
Resources to lauch GitHub app
Browse files Browse the repository at this point in the history
Signed-off-by: Prudhvi Godithi <[email protected]>
  • Loading branch information
prudhvigodithi committed Oct 1, 2024
1 parent d8b52e6 commit ab3958e
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 2 deletions.
1 change: 1 addition & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ So you want to contribute code to this project? Excellent! We're glad you're her
- `cdk deploy OpenSearchMetricsNginxReadonly`: To deploy the dashboard read only setup.
- `cdk deploy OpenSearchWAF`: To deploy the AWS WAF for the project ALB's.
- `cdk deploy OpenSearchMetrics-Monitoring`: To deploy the alerting stack which will monitor the step functions and URL of the project coming from [METRICS_HOSTED_ZONE](https://github.com/opensearch-project/opensearch-metrics/blob/main/infrastructure/lib/enums/project.ts)
- `cdk deploy OpenSearchMetrics-GitHubApp`: Create the resources which launches the GitHub App. Listens to GitHub events and index the data to Metrics cluster.

### Forking and Cloning

Expand Down
19 changes: 17 additions & 2 deletions infrastructure/lib/infrastructure-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { OpenSearchWAF } from "./stacks/waf";
import { OpenSearchMetricsNginxCognito } from "./constructs/opensearchNginxProxyCognito";
import { OpenSearchMetricsMonitoringStack } from "./stacks/monitoringDashboard";
import { OpenSearchMetricsSecretsStack } from "./stacks/secrets";
import {GitHubApp} from "./stacks/gitHubApp";

// import * as sqs from 'aws-cdk-lib/aws-sqs';
export class InfrastructureStack extends Stack {
Expand All @@ -29,6 +30,21 @@ export class InfrastructureStack extends Stack {
// Create VPC for the entire setup
const vpcStack = new VpcStack(app, "OpenSearchHealth-VPC", {});

// Create secret related to Github App
const openSearchMetricsGitHubAppSecretStack = new OpenSearchMetricsSecretsStack(app, "OpenSearchMetrics-GitHubAppSecret", {
secretName: 'github-app-creds'
});

// Create resources to launch the Github App
const gitHubApp = new GitHubApp(app, "OpenSearchMetrics-GitHubApp", {
vpc: vpcStack.vpc,
region: Project.REGION,
account: Project.AWS_ACCOUNT,
ami: Project.EC2_AMI_SSM.toString(),
secret: openSearchMetricsGitHubAppSecretStack.secret
})
gitHubApp.node.addDependency(vpcStack, openSearchMetricsGitHubAppSecretStack);


// Create OpenSearch Domain, roles, permissions, cognito setup, cross account OpenSearch access for jenkins
const openSearchDomainStack = new OpenSearchDomainStack(app, "OpenSearchHealth-OpenSearch", {
Expand All @@ -50,8 +66,7 @@ export class InfrastructureStack extends Stack {
})
openSearchMetricsWorkflowStack.node.addDependency(vpcStack, openSearchDomainStack);

// Create Secrets Manager

// Create Secret Manager for the metrics project
const openSearchMetricsSecretsStack = new OpenSearchMetricsSecretsStack(app, "OpenSearchMetrics-Secrets", {
secretName: 'metrics-creds'
});
Expand Down
138 changes: 138 additions & 0 deletions infrastructure/lib/stacks/gitHubApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

import {Aspects, Duration, Stack, Tag, Tags} from 'aws-cdk-lib';
import {
AutoScalingGroup,
BlockDeviceVolume,
CfnLaunchConfiguration,
HealthCheck,
UpdatePolicy
} from 'aws-cdk-lib/aws-autoscaling';
import {
InstanceClass,
InstanceSize,
InstanceType,
MachineImage,
SubnetType,
Vpc
} from 'aws-cdk-lib/aws-ec2';
import {
ArnPrincipal,
CompositePrincipal,
Effect,
ManagedPolicy,
PolicyStatement,
Role,
ServicePrincipal
} from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import {OpenSearchMetricsSecretsStack} from "./secrets";
import {Secret} from "aws-cdk-lib/aws-secretsmanager";


export interface GitHubAppProps {
readonly vpc: Vpc;
readonly region: string;
readonly account: string;
readonly ami?: string
readonly secret: Secret;
}


export class GitHubApp extends Stack {

readonly asg: AutoScalingGroup;
readonly githubAppRole: Role;

constructor(scope: Construct, id: string, props: GitHubAppProps) {
super(scope, id);

const instanceRole = this.createInstanceRole(props.secret.secretArn, props.account);
this.githubAppRole = instanceRole;

this.asg = new AutoScalingGroup(this, 'OpenSearchMetrics-GitHubAppAsg', {
instanceType: InstanceType.of(InstanceClass.M5, InstanceSize.LARGE),
blockDevices: [{ deviceName: '/dev/xvda', volume: BlockDeviceVolume.ebs(10) }],
healthCheck: HealthCheck.ec2({ grace: Duration.seconds(90) }),
machineImage: props && props.ami ?
MachineImage.fromSsmParameter(props.ami) :

Check warning on line 64 in infrastructure/lib/stacks/gitHubApp.ts

View check run for this annotation

Codecov / codecov/patch

infrastructure/lib/stacks/gitHubApp.ts#L64

Added line #L64 was not covered by tests
MachineImage.latestAmazonLinux2(),
associatePublicIpAddress: false,
allowAllOutbound: true,
desiredCapacity: 1,
minCapacity: 1,
vpc: props.vpc,
vpcSubnets: {
subnetType: SubnetType.PRIVATE_WITH_EGRESS
},
role: instanceRole,
updatePolicy: UpdatePolicy.replacingUpdate()
});
Tags.of(this.asg).add("Name", "OpenSearchMetrics-GitHubApp")


const launchConfiguration = this.asg.node.findChild('LaunchConfig') as CfnLaunchConfiguration;
launchConfiguration.metadataOptions = {
httpPutResponseHopLimit: 2,
httpEndpoint: "enabled",
httpTokens: "required"
};

const instanceName = 'OpenSearchMetrics-GitHubAppHost';
Aspects.of(this.asg).add(new Tag('name', instanceName, {
applyToLaunchedInstances: true,
includeResourceTypes: ['AWS::AutoScaling::AutoScalingGroup']
}),);
this.asg.addUserData(...this.getUserData(props.secret.secretName));
}

private createInstanceRole(secretArn: string, account: string): Role {
const role = new Role(this, "OpenSearchMetrics-GitHubAppRole", {
assumedBy: new CompositePrincipal(
new ServicePrincipal('ec2.amazonaws.com'),
new ArnPrincipal(`arn:aws:iam::${account}:role/OpenSearchMetrics-GitHubAppRole`)
),
roleName: "OpenSearchMetrics-GitHubAppRole",
});
role.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'));
role.addToPolicy(
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["secretsmanager:GetSecretValue"],
resources: [secretArn],
}),
);
role.addToPolicy(
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["sts:AssumeRole"],
resources: [role.roleArn],
}),
);
return role;
}


private getUserData(secretName: string): string[] {
return [
'sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm',
'sudo dnf update -y',
'sudo yum install git docker -y',
'sudo systemctl enable docker',
'sudo systemctl start docker',
'sudo curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/sbin/docker-compose',
'sudo chmod a+x /usr/local/sbin/docker-compose',
'git clone https://github.com/opensearch-project/automation-app.git',
`aws secretsmanager get-secret-value --secret-id ${secretName} --query SecretString --output text >> automation-app/.env`,
'cd automation-app/docker',
'PORT=8080 OPERATION_CONFIG=configs/operations/github-merged-pulls-monitor.yml docker-compose -p automation-app-1 up -d',
'PORT=8081 OPERATION_CONFIG=configs/operations/github-workflow-runs-monitor.yml docker-compose -p automation-app-2 up -d'
];
}
}
68 changes: 68 additions & 0 deletions infrastructure/test/gitHubApp-stack.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

import { App } from "aws-cdk-lib";
import {Match, Template} from "aws-cdk-lib/assertions";
import Project from "../lib/enums/project";
import { VpcStack } from "../lib/stacks/vpc";
import {GitHubApp} from "../lib/stacks/gitHubApp";
import {OpenSearchMetricsSecretsStack} from "../lib/stacks/secrets";


test('OpenSearch GitHub App Stack test ', () => {
const app = new App();
const vpcStack = new VpcStack(app, "Test-OpenSearchHealth-VPC", {});
const openSearchMetricsGitHubAppSecretStack = new OpenSearchMetricsSecretsStack(app, "Test-OpenSearchMetrics-GitHubAppSecret", {
secretName: 'test-github-app-creds'
});
const gitHubApp = new GitHubApp(app, "Test-OpenSearchMetrics-GitHubApp", {
vpc: vpcStack.vpc,
region: Project.REGION,
account: Project.AWS_ACCOUNT,
ami: Project.EC2_AMI_SSM.toString(),
secret: openSearchMetricsGitHubAppSecretStack.secret
});

const template = Template.fromStack(gitHubApp);
template.resourceCountIs('AWS::IAM::Role', 1);
template.hasResourceProperties('AWS::IAM::Role', {
AssumeRolePolicyDocument: {
Statement: Match.arrayWith([
{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "ec2.amazonaws.com"
}
}
])
}
});
template.hasResourceProperties('AWS::EC2::SecurityGroup', {
GroupDescription: Match.stringLikeRegexp('Test-OpenSearchMetrics-GitHubApp/OpenSearchMetrics-GitHubAppAsg/InstanceSecurityGroup')
});
template.resourceCountIs('AWS::IAM::Policy', 1);
template.hasResourceProperties('AWS::IAM::Policy', {
PolicyDocument: {
Statement: Match.arrayWith([
Match.objectLike({
Action: "secretsmanager:GetSecretValue",
Effect: "Allow",
Resource: {
"Fn::ImportValue": Match.stringLikeRegexp('Test-OpenSearchMetrics-GitHubAppSecret:ExportsOutputRefMetricsCreds.*')
}
})
])
}
});
template.hasResourceProperties('AWS::AutoScaling::AutoScalingGroup', {
DesiredCapacity: "1",
MaxSize: "1",
MinSize: "1",
})
});

0 comments on commit ab3958e

Please sign in to comment.