Skip to content

Commit

Permalink
Merge pull request opensearch-project#987 from AndreKurait/CDKSonarQube
Browse files Browse the repository at this point in the history
Cdk maintenance and tests
  • Loading branch information
AndreKurait authored Sep 20, 2024
2 parents d6a4e82 + e9ed46b commit 492e5b9
Show file tree
Hide file tree
Showing 16 changed files with 341 additions and 105 deletions.
27 changes: 3 additions & 24 deletions deployment/cdk/opensearch-service-migration/bin/app.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,6 @@
#!/usr/bin/env node
import 'source-map-support/register';
import {readFileSync} from 'fs';
import {App, Tags} from 'aws-cdk-lib';
import {StackComposer} from "../lib/stack-composer";
import { createApp } from './createApp';

const app = new App();
const versionFile = readFileSync('../../../VERSION', 'utf-8')
// Remove any blank newlines because this would be an invalid tag value
const version = versionFile.replace(/\n/g, '');
Tags.of(app).add("migration_deployment", version)
const account = process.env.CDK_DEFAULT_ACCOUNT
const region = process.env.CDK_DEFAULT_REGION
// Environment setting to allow providing an existing AWS AppRegistry application ARN which each created CDK stack
// from this CDK app will be added to.
const migrationsAppRegistryARN = process.env.MIGRATIONS_APP_REGISTRY_ARN
if (migrationsAppRegistryARN) {
console.info(`App Registry mode is enabled for CFN stack tracking. Will attempt to import the App Registry application from the MIGRATIONS_APP_REGISTRY_ARN env variable of ${migrationsAppRegistryARN} and looking in the configured region of ${region}`)
}
const customReplayerUserAgent = process.env.CUSTOM_REPLAYER_USER_AGENT

new StackComposer(app, {
migrationsAppRegistryARN: migrationsAppRegistryARN,
customReplayerUserAgent: customReplayerUserAgent,
migrationsSolutionVersion: version,
env: { account: account, region: region }
});
const app = createApp();
app.synth();
28 changes: 28 additions & 0 deletions deployment/cdk/opensearch-service-migration/bin/createApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { App, Tags } from 'aws-cdk-lib';
import { readFileSync } from 'fs';
import { StackComposer } from "../lib/stack-composer";

export function createApp(): App {
const app = new App();
const versionFile = readFileSync('../../../VERSION', 'utf-8');
const version = versionFile.replace(/\n/g, '');
Tags.of(app).add("migration_deployment", version);

const account = process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEFAULT_REGION;
const migrationsAppRegistryARN = process.env.MIGRATIONS_APP_REGISTRY_ARN;
const customReplayerUserAgent = process.env.CUSTOM_REPLAYER_USER_AGENT;

if (migrationsAppRegistryARN) {
console.info(`App Registry mode is enabled for CFN stack tracking. Will attempt to import the App Registry application from the MIGRATIONS_APP_REGISTRY_ARN env variable of ${migrationsAppRegistryARN} and looking in the configured region of ${region}`);
}

new StackComposer(app, {
migrationsAppRegistryARN: migrationsAppRegistryARN,
customReplayerUserAgent: customReplayerUserAgent,
migrationsSolutionVersion: version,
env: { account: account, region: region }
});

return app;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import {Effect, PolicyStatement, Role, ServicePrincipal} from "aws-cdk-lib/aws-i
import {Construct} from "constructs";
import {CpuArchitecture} from "aws-cdk-lib/aws-ecs";
import {RemovalPolicy} from "aws-cdk-lib";
import { IApplicationLoadBalancer } from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
import { IStringParameter, StringParameter } from "aws-cdk-lib/aws-ssm";
import * as forge from 'node-forge';
import * as yargs from 'yargs';
Expand Down Expand Up @@ -211,20 +209,18 @@ export function createDefaultECSTaskRole(scope: Construct, serviceName: string):
}

export function validateFargateCpuArch(cpuArch?: string): CpuArchitecture {
const desiredArch = cpuArch ? cpuArch : process.arch
const desiredArch = cpuArch ?? process.arch
const desiredArchUpper = desiredArch.toUpperCase()

if (desiredArchUpper === "X86_64" || desiredArchUpper === "X64") {
return CpuArchitecture.X86_64
} else if (desiredArchUpper === "ARM64") {
return CpuArchitecture.ARM64
} else {
if (cpuArch) {
throw new Error(`Unknown Fargate cpu architecture provided: ${desiredArch}`)
}
else {
throw new Error(`Unsupported process cpu architecture detected: ${desiredArch}, CDK requires X64 or ARM64 for Docker image compatability`)
}
} else if (cpuArch) {
throw new Error(`Unknown Fargate cpu architecture provided: ${desiredArch}`)
}
else {
throw new Error(`Unsupported process cpu architecture detected: ${desiredArch}, CDK requires X64 or ARM64 for Docker image compatability`)
}
}

Expand All @@ -235,21 +231,6 @@ export function parseRemovalPolicy(optionName: string, policyNameString?: string
}
return policy
}


export type ALBConfig = NewALBListenerConfig;

export interface NewALBListenerConfig {
alb: IApplicationLoadBalancer,
albListenerCert: ICertificate,
albListenerPort?: number,
}

export function isNewALBListenerConfig(config: ALBConfig): config is NewALBListenerConfig {
const parsed = config as NewALBListenerConfig;
return parsed.alb !== undefined && parsed.albListenerCert !== undefined;
}

export function hashStringSHA256(message: string): string {
const md = forge.md.sha256.create();
md.update(message);
Expand Down Expand Up @@ -317,7 +298,7 @@ export enum MigrationSSMParameter {
}


export class ClusterNoAuth {};
export class ClusterNoAuth {}

export class ClusterSigV4Auth {
region?: string;
Expand Down Expand Up @@ -443,4 +424,4 @@ export function parseClusterDefinition(json: any): ClusterYaml {
throw new Error(`Invalid auth type when parsing cluster definition: ${json.auth.type}`)
}
return new ClusterYaml({endpoint, version, auth})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,26 @@ export const handler = async (event: CloudFormationCustomResourceEvent, context:

try {
switch (event.RequestType) {
case 'Create':
case 'Create': {
const { certificate, privateKey, certificateChain } = await generateSelfSignedCertificate();
const certificateArn = await importCertificate(certificate, privateKey, certificateChain);
console.log(`Certificate imported with ARN: ${certificateArn}`);
responseData = { CertificateArn: certificateArn };
physicalResourceId = certificateArn;
break;
case 'Update':
}
case 'Update': {
// No update logic needed, return existing physical resource id
physicalResourceId = event.PhysicalResourceId;
break;
case 'Delete':
break;
}
case 'Delete': {
const arn = event.PhysicalResourceId;
await deleteCertificate(arn);
responseData = { CertificateArn: arn };
physicalResourceId = arn;
break;
}
}

return await sendResponse(event, context, 'SUCCESS', responseData, physicalResourceId);
Expand All @@ -45,7 +48,7 @@ async function generateSelfSignedCertificate(): Promise<{ certificate: string, p
return new Promise((resolve, reject) => {
const keys = forge.pki.rsa.generateKeyPair(2048);
const cert = forge.pki.createCertificate();

cert.publicKey = keys.publicKey;
cert.serialNumber = '01';
cert.validity.notBefore = new Date(Date.UTC(1970, 0, 1, 0, 0, 0));
Expand All @@ -54,10 +57,10 @@ async function generateSelfSignedCertificate(): Promise<{ certificate: string, p
name: 'commonName',
value: 'localhost'
}];

cert.setSubject(attrs);
cert.setIssuer(attrs);

cert.setExtensions([{
name: 'basicConstraints',
cA: true
Expand All @@ -78,7 +81,7 @@ async function generateSelfSignedCertificate(): Promise<{ certificate: string, p
clientAuth: true
},]);
cert.sign(keys.privateKey, forge.md.sha384.create());

const pemCert = forge.pki.certificateToPem(cert);
const pemKey = forge.pki.privateKeyToPem(keys.privateKey);

Expand Down Expand Up @@ -165,12 +168,12 @@ async function sendResponse(event: CloudFormationCustomResourceEvent, context: C
});
});

request.on('error', (error) => {
request.on('error', (error: Error) => {
console.error('sendResponse Error:', error);
reject(error);
});

request.write(responseBody);
request.end();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,6 @@ export class MetadataMigrationYaml {
otel_endpoint: string = '';
source_cluster_version?: string;
}

export class MSKYaml {
}

export class StandardKafkaYaml {
}

export class KafkaYaml {
broker_endpoints: string = '';
msk?: string | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class NetworkStack extends Stack {
this.vpc = new Vpc(this, 'domainVPC', {
// IP space should be customized for use cases that have specific IP range needs
ipAddresses: IpAddresses.cidr('10.0.0.0/16'),
maxAzs: zoneCount ? zoneCount : 2,
maxAzs: zoneCount ?? 2,
subnetConfiguration: [
// Outbound internet access for private subnets require a NAT Gateway which must live in
// a public subnet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@ import {ILogGroup, LogGroup} from "aws-cdk-lib/aws-logs";
import {ISecret, Secret} from "aws-cdk-lib/aws-secretsmanager";
import {StackPropsExt} from "./stack-composer";
import { ClusterYaml } from "./migration-services-yaml";
import { ClusterAuth, ClusterBasicAuth, ClusterNoAuth } from "./common-utilities"
import { MigrationSSMParameter, createMigrationStringParameter, getMigrationStringParameterValue } from "./common-utilities";
import {
ClusterAuth,
ClusterBasicAuth,
ClusterNoAuth,
MigrationSSMParameter,
createMigrationStringParameter,
getMigrationStringParameterValue
} from "./common-utilities";


export interface OpensearchDomainStackProps extends StackPropsExt {
Expand Down Expand Up @@ -56,8 +62,6 @@ export interface OpensearchDomainStackProps extends StackPropsExt {
}


export const osClusterEndpointParameterName = "osClusterEndpoint";

export class OpenSearchDomainStack extends Stack {
targetClusterYaml: ClusterYaml;

Expand Down Expand Up @@ -99,19 +103,18 @@ export class OpenSearchDomainStack extends Stack {
}

createSSMParameters(domain: Domain, adminUserName: string|undefined, adminUserSecret: ISecret|undefined, stage: string, deployId: string) {
const endpointParameter = osClusterEndpointParameterName
const endpointSSM = createMigrationStringParameter(this, `https://${domain.domainEndpoint}:443`, {
createMigrationStringParameter(this, `https://${domain.domainEndpoint}:443`, {
parameter: MigrationSSMParameter.OS_CLUSTER_ENDPOINT,
defaultDeployId: deployId,
stage,
});
if (domain.masterUserPassword && !adminUserSecret) {
console.log(`An OpenSearch domain fine-grained access control user was configured without an existing Secrets Manager secret, will not create SSM Parameter: /migration/${stage}/${deployId}/osUserAndSecret`)
} else if (domain.masterUserPassword && adminUserSecret) {
const secretSSM = createMigrationStringParameter(this, `${adminUserName} ${adminUserSecret.secretArn}`, {
createMigrationStringParameter(this, `${adminUserName} ${adminUserSecret.secretArn}`, {
parameter: MigrationSSMParameter.OS_USER_AND_SECRET_ARN,
defaultDeployId: deployId,
stage,
stage,
});
}
}
Expand All @@ -138,12 +141,11 @@ export class OpenSearchDomainStack extends Stack {
const appLG: ILogGroup|undefined = props.appLogGroup && props.appLogEnabled ?
LogGroup.fromLogGroupArn(this, "appLogGroup", props.appLogGroup) : undefined

const domainAccessSecurityGroupParameter = props.domainAccessSecurityGroupParameter ?? "osAccessSecurityGroupId"
const defaultOSClusterAccessGroup = SecurityGroup.fromSecurityGroupId(this, "defaultDomainAccessSG", getMigrationStringParameterValue(this, {
...props,
parameter: MigrationSSMParameter.OS_ACCESS_SECURITY_GROUP_ID,
}));

let adminUserSecret: ISecret|undefined = props.fineGrainedManagerUserSecretManagerKeyARN ?
Secret.fromSecretCompleteArn(this, "managerSecret", props.fineGrainedManagerUserSecretManagerKeyARN) : undefined
// Map objects from props
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class CaptureProxyStack extends MigrationServiceCore {

constructor(scope: Construct, id: string, props: CaptureProxyProps) {
super(scope, id, props)
const serviceName = props.serviceName || "capture-proxy";
const serviceName = props.serviceName ?? "capture-proxy";

let securityGroupConfigs = [
{ id: "serviceSG", param: MigrationSSMParameter.SERVICE_SECURITY_GROUP_ID },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {StackPropsExt} from "../stack-composer";
import {IVpc, SecurityGroup} from "aws-cdk-lib/aws-ec2";
import {CpuArchitecture, MountPoint, PortMapping, Protocol, Volume} from "aws-cdk-lib/aws-ecs";
import {CpuArchitecture, PortMapping, Protocol} from "aws-cdk-lib/aws-ecs";
import {Construct} from "constructs";
import {join} from "path";
import {Effect, PolicyStatement, Role, ServicePrincipal} from "aws-cdk-lib/aws-iam";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { DockerImageAsset } from "aws-cdk-lib/aws-ecr-assets";
import { join } from "path";

export class OtelCollectorSidecar {
public static OTEL_CONTAINER_PORT = 4317;
public static OTEL_CONTAINER_HEALTHCHECK_PORT = 13133;
public static readonly OTEL_CONTAINER_PORT = 4317;
public static readonly OTEL_CONTAINER_HEALTHCHECK_PORT = 13133;

static getOtelLocalhostEndpoint() {
return "http://localhost:" + OtelCollectorSidecar.OTEL_CONTAINER_PORT;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {StackPropsExt} from "../stack-composer";
import {ISecurityGroup, IVpc, SubnetType} from "aws-cdk-lib/aws-ec2";
import {
CfnService as FargateCfnService,
Cluster,
ContainerImage, CpuArchitecture,
FargateService,
Expand Down Expand Up @@ -140,8 +139,8 @@ export class MigrationServiceCore extends Stack {
let startupPeriodSeconds = 30;
// Add a separate container to monitor and fail healthcheck after a given maxUptime
const maxUptimeContainer = serviceTaskDef.addContainer("MaxUptimeContainer", {
image: ContainerImage.fromRegistry("public.ecr.aws/amazonlinux/amazonlinux:2023-minimal"),
memoryLimitMiB: 64,
image: ContainerImage.fromRegistry("public.ecr.aws/amazonlinux/amazonlinux:2023-minimal"),
memoryLimitMiB: 64,
entryPoint: [
"/bin/sh",
"-c",
Expand Down Expand Up @@ -185,10 +184,10 @@ export class MigrationServiceCore extends Stack {
securityGroups: props.securityGroups,
vpcSubnets: props.vpc.selectSubnets({subnetType: SubnetType.PRIVATE_WITH_EGRESS}),
});

if (props.targetGroups) {
props.targetGroups.filter(tg => tg !== undefined).forEach(tg => tg.addTarget(fargateService));
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ export class ReindexFromSnapshotStack extends MigrationServiceCore {
let targetPassword = "";
let targetPasswordArn = "";
if (props.clusterAuthDetails.basicAuth) {
targetUser = props.clusterAuthDetails.basicAuth.username,
targetPassword = props.clusterAuthDetails.basicAuth.password || "",
targetPasswordArn = props.clusterAuthDetails.basicAuth.password_from_secret_arn || ""
targetUser = props.clusterAuthDetails.basicAuth.username
targetPassword = props.clusterAuthDetails.basicAuth.password ?? ""
targetPasswordArn = props.clusterAuthDetails.basicAuth.password_from_secret_arn ?? ""
};
const sharedLogFileSystem = new SharedLogFileSystem(this, props.stage, props.defaultDeployId);
const openSearchPolicy = createOpenSearchIAMAccessPolicy(this.partition, this.region, this.account);
Expand Down
Loading

0 comments on commit 492e5b9

Please sign in to comment.