Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use private s3 sdk assets via cloudfront for hyperloader #135

Merged
merged 12 commits into from
May 9, 2024
2 changes: 1 addition & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ if [[ "$INSTALLATION_MODE" == 2 ]]; then
echo "Please enter the password for your RDS instance (Minimum 8 characters; includes [A-Z], [a-z], [0-9]): "
read -r -s LOCKER_DB_PASS
if validate_password "$LOCKER_DB_PASS"; then
break
breakup
fi
done
LOCKER+="-c locker_pass=$LOCKER_DB_PASS "
Expand Down
99 changes: 72 additions & 27 deletions lib/aws/eks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { LockerSetup } from "./card-vault/components";
import { Trigger } from "aws-cdk-lib/triggers";
import * as codebuild from "aws-cdk-lib/aws-codebuild";
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as s3 from 'aws-cdk-lib/aws-s3';
// import { LockerSetup } from "./card-vault/components";

export class EksStack {
sg: ec2.ISecurityGroup;
hyperswitchHost: string;
lokiChart: eks.HelmChart;
sdkBucket: s3.Bucket;
sdkDistribution: cloudfront.CloudFrontWebDistribution;
constructor(
scope: Construct,
config: Config,
Expand Down Expand Up @@ -304,30 +308,30 @@ export class EksStack {

const kmsSecrets = new KmsSecrets(scope, triggerKMSEncryption);

const delete_stack_code = readFileSync(
"lib/aws/delete_stack.py",
).toString();


const delete_stack_function = new Function(scope, "hyperswitch-stack-delete", {
functionName: "HyperswitchStackDeletionLambda",
runtime: Runtime.PYTHON_3_9,
handler: "index.lambda_handler",
code: Code.fromInline(delete_stack_code),
timeout: cdk.Duration.minutes(15),
role: lambda_role,
environment: {
SECRET_MANAGER_ARN: secret.secretArn,
},
});
// const delete_stack_code = readFileSync(
// "lib/aws/delete_stack.py",
// ).toString();


// const delete_stack_function = new Function(scope, "hyperswitch-stack-delete", {
// functionName: "HyperswitchStackDeletionLambda",
// runtime: Runtime.PYTHON_3_9,
// handler: "index.lambda_handler",
// code: Code.fromInline(delete_stack_code),
// timeout: cdk.Duration.minutes(15),
// role: lambda_role,
// environment: {
// SECRET_MANAGER_ARN: secret.secretArn,
// },
// });

new cdk.CustomResource(
scope,
"HyperswitchStackDeletionCR",
{
serviceToken: delete_stack_function.functionArn,
},
);
// new cdk.CustomResource(
// scope,
// "HyperswitchStackDeletionCR",
// {
// serviceToken: delete_stack_function.functionArn,
// },
// );

// Create a security group for the load balancer
const lbSecurityGroup = new ec2.SecurityGroup(scope, "HSLBSecurityGroup", {
Expand Down Expand Up @@ -438,6 +442,44 @@ export class EksStack {
},
});

const sdkCorsRule: s3.CorsRule = {
allowedOrigins: ["*"],
allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.HEAD],
allowedHeaders: ["*"],
maxAge: 3000,
}

let sdkBucket = new s3.Bucket(scope, "HyperswitchSDKBucket", {
bucketName: `hyperswitch-sdk-${process.env.CDK_DEFAULT_ACCOUNT}-${process.env.CDK_DEFAULT_REGION}`,
blockPublicAccess: new s3.BlockPublicAccess({
blockPublicAcls: true,
}),
publicReadAccess: false,
removalPolicy: cdk.RemovalPolicy.DESTROY,
cors: [sdkCorsRule],
autoDeleteObjects: true,
});

const oai = new cloudfront.OriginAccessIdentity(scope, 'SdkOAI');
sdkBucket.grantRead(oai);

this.sdkDistribution = new cloudfront.CloudFrontWebDistribution(scope, 'sdkDistribution', {
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.ALLOW_ALL,
originConfigs: [
{
s3OriginSource: {
s3BucketSource: sdkBucket,
originAccessIdentity: oai,
},
behaviors: [{isDefaultBehavior: true}, {pathPattern: '/*', allowedMethods: cloudfront.CloudFrontAllowedMethods.GET_HEAD}]
}
]
});
this.sdkDistribution.node.addDependency(sdkBucket);
new cdk.CfnOutput(scope, 'SdkDistribution', {
value: this.sdkDistribution.distributionDomainName,
});

const sdk_version = "0.27.2";
const hypersChart = cluster.addHelmChart("HyperswitchServices", {
chart: "hyperswitch-stack",
Expand Down Expand Up @@ -509,7 +551,7 @@ export class EksStack {
recon_admin_api_key: kmsSecrets.kms_recon_admin_api_key,
forex_api_key: kmsSecrets.kms_forex_api_key,
forex_fallback_api_key: kmsSecrets.kms_forex_fallback_api_key,
apple_pay_ppc: kmsSecrets.apple_pay_ppc,
apple_pay_ppc: kmsSecrets.apple_pay_ppc,
apple_pay_ppc_key: kmsSecrets.apple_pay_ppc_key,
apple_pay_merchant_cert: kmsSecrets.apple_pay_merchant_conf_merchant_cert,
apple_pay_merchant_cert_key: kmsSecrets.apple_pay_merchant_conf_merchant_cert_key,
Expand Down Expand Up @@ -551,7 +593,6 @@ export class EksStack {
password: kmsSecrets.kms_encrypted_db_pass,
plainpassword: config.rds.password,
},

}
},

Expand Down Expand Up @@ -623,16 +664,20 @@ export class EksStack {
]
},
autoBuild: {
forceBuild: true,
forceBuild: false,
gitCloneParam: {
gitVersion: sdk_version
},
nginxConfig: { extraPath: "v0" }
buildParam: {
envSdkUrl: `http://${this.sdkDistribution.distributionDomainName}`
},
// nginxConfig: { extraPath: "v0" }
}
},
},
});

this.sdkBucket = sdkBucket;
hypersChart.node.addDependency(albControllerChart, triggerKMSEncryption);

const conditions = new cdk.CfnJson(scope, "ConditionJson", {
Expand Down
152 changes: 152 additions & 0 deletions lib/aws/hs-sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import * as ec2 from "aws-cdk-lib/aws-ec2";
import { Construct } from "constructs";
import * as codebuild from "aws-cdk-lib/aws-codebuild";
import { Config } from "./config";
import * as cr from "aws-cdk-lib/custom-resources";
import { PolicyStatement } from "aws-cdk-lib/aws-iam";
import * as cdk from "aws-cdk-lib/core";
import * as s3 from 'aws-cdk-lib/aws-s3';
import { EksStack } from "./eks";
import * as iam from "aws-cdk-lib/aws-iam";
import { readFileSync } from "fs";
import { Code, Function, Runtime } from "aws-cdk-lib/aws-lambda";

export class HyperswitchSDKStack {
constructor(
scope: Construct,
eks: EksStack,
) {

const sdkBuildRole = new iam.Role(scope, "sdkBucketRole", {
assumedBy: new iam.ServicePrincipal("codebuild.amazonaws.com"),
});

const sdkBuildPolicy = new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: [
"s3:putObject",
"s3:getObject",
"s3:ListBucket",
"elasticloadbalancing:DescribeLoadBalancers",
],
resources: ["*"],
}),
]
});

sdkBuildRole.attachInlinePolicy(
new iam.Policy(scope, "SDKBucketAccessPolicy", {
document: sdkBuildPolicy,
}),
);

let sdkVersion = "0.27.2";

// Create a new CodeBuild project
const project = new codebuild.Project(scope, "HyperswitchSDK", {
projectName: "HyperswitchSDK",
role: sdkBuildRole,
buildSpec: codebuild.BuildSpec.fromObject({
version: "0.2",
phases: {
install: {
commands: [
"export envBackendUrl=\"http://$(aws elbv2 describe-load-balancers --name 'hyperswitch' --query 'LoadBalancers[].DNSName' --output text)\"",
"git clone --branch v"+sdkVersion+" https://github.com/juspay/hyperswitch-web",
"cd hyperswitch-web",
"n install 18",
"npm -v",
"node --version",
"npm install",
"npm run re:build",
],
},
build: {
commands: "envSdkUrl=$envSdkUrl envBackendUrl=$envBackendUrl npm run build:integ",
},
post_build: {
commands: [
"aws s3 cp --recursive dist/integ/ s3://$sdkBucket/"+sdkVersion+"/v0",
],
},
},
}),
environmentVariables: {
sdkBucket: {
value: eks.sdkBucket.bucketName,
type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
},
envSdkUrl: {
value: "http://" + eks.sdkDistribution.distributionDomainName,
type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
},
},
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_5,
},
});
// Allow the CodeBuild project to access the S3 bucket
eks.sdkBucket.grantReadWrite(project);

project.node.addDependency(eks.lokiChart);

const lambdaStartBuildCode = readFileSync('./dependencies/code_builder/start_build.py').toString();

const triggerCodeBuildRole = new iam.Role(scope, "SdkAssetsUploadLambdaRole", {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
});

const triggerCodeBuildPolicy = new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: [
"codebuild:StartBuild",
],
resources: [project.projectArn],
}),
]
});

const logsPolicy = new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
],
resources: ["*"],
})
]
})

triggerCodeBuildRole.attachInlinePolicy(
new iam.Policy(scope, "SdkAssetsUploadLambdaPolicy", {
document: triggerCodeBuildPolicy,
}),
);

triggerCodeBuildRole.attachInlinePolicy(
new iam.Policy(scope, "SdkAssetsUploadLambdaLogsPolicy", {
document: logsPolicy,
}),
);

const triggerCodeBuild = new Function(scope, "SdkAssetsUploadLambda", {
runtime: Runtime.PYTHON_3_9,
handler: "index.lambda_handler",
code: Code.fromInline(lambdaStartBuildCode),
timeout: cdk.Duration.minutes(15),
role: triggerCodeBuildRole,
environment: {
PROJECT_NAME: project.projectName,
},
});

const codebuildTrigger = new cdk.CustomResource(scope, "SdkAssetsUploadCR", {
serviceToken: triggerCodeBuild.functionArn,
});

}
}
3 changes: 2 additions & 1 deletion lib/aws/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SubnetStack } from "./subnet";
import { EC2Instance } from "./ec2";
import { LockerSetup } from "./card-vault/components";
import { DatabaseInstance } from "aws-cdk-lib/aws-rds";
import { HyperswitchSDKStack } from "./hs-sdk";

export class AWSStack extends cdk.Stack {
constructor(scope: Construct, config: Config) {
Expand Down Expand Up @@ -150,7 +151,7 @@ export class AWSStack extends cdk.Stack {
if (locker) locker.locker_ec2.addClient(eks.sg, ec2.Port.tcp(8080));
rds.sg.addIngressRule(eks.sg, ec2.Port.tcp(5432));
elasticache.sg.addIngressRule(eks.sg, ec2.Port.tcp(6379));
// let hsSdk = new HyperswitchSDKStack(this, config, vpc.vpc, rds, eks);
let hsSdk = new HyperswitchSDKStack(this, eks);

// Create Jumps and add rules to access RDS, Elasticache and Proxies
// Internal Jump can be accessed only from external jump. External jump can be accessed only from Session Manager
Expand Down
4 changes: 2 additions & 2 deletions lib/aws/userdata.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ docker run -d --env-file .env -p 80:8080 -v `pwd`/:/local/config juspaydotin/hyp

# Installing Hyperswitch control center

docker pull juspaydotin/hyperswitch-control-center:v1.17.0
docker pull juspaydotin/hyperswitch-control-center:v1.29.9

cat << EOF >> .env
apiBaseUrl=http://$(curl ifconfig.me):80
sdkBaseUrl=http://$(curl ifconfig.me):80
EOF

docker run -d --env-file .env -p 9000:9000 juspaydotin/hyperswitch-control-center:v1.17.0
docker run -d --env-file .env -p 9000:9000 juspaydotin/hyperswitch-control-center:v1.29.9
2 changes: 0 additions & 2 deletions uninstall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ for lb in "${load_balancers[@]}"; do
aws elbv2 delete-load-balancer --load-balancer-arn $lb_arn
done

# destroy the stack
AWS_ARN=$(aws sts get-caller-identity --output json | jq -r .Arn )
# destroy the stack
AWS_ARN=$(aws sts get-caller-identity --output json | jq -r .Arn )
cdk destroy --require-approval never -c aws_arn=$AWS_ARN --force
7 changes: 3 additions & 4 deletions upgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ ADMIN_API_KEY=$1
APP_HOST=$(kubectl get ingress hyperswitch-alb-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
LOGS_HOST=$(kubectl get ingress hyperswitch-logs-alb-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
CONTROL_CENTER_HOST=$(kubectl get ingress hyperswitch-control-center-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
SDK_WEB_HOST=$(kubectl get ingress hyperswitch-web-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
SDK_HOST=$(kubectl get ingress hyperswitch-sdk-demo-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
SDK_URL=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='HyperLoaderUrl'].OutputValue" --output text)
SDK_URL=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='SdkDistribution'].OutputValue" --output text)

# Deploy the hyperswitch application with the load balancer host name
helm repo add hs https://juspay.github.io/hyperswitch-helm/v0.1.2 --force-update
Expand All @@ -47,8 +46,8 @@ printf "##########################################\nPlease wait for the applicat
APP_ENV="hyperswitch-app"
SDK_ENV="hyperswitchsdk.services"
SDK_BUILD="hyperswitchsdk.autoBuild.buildParam"
HYPERLOADER="http://$SDK_WEB_HOST/0.27.2/v0/HyperLoader.js"
helm upgrade --install hypers-v1 hs/hyperswitch-stack --set "$SDK_ENV.router.host=http://$APP_HOST,$SDK_ENV.sdkDemo.hyperswitchPublishableKey=$PUB_KEY,$SDK_ENV.sdkDemo.hyperswitchSecretKey=$API_KEY,$APP_ENV.services.sdk.host=http://$SDK_WEB_HOST,$APP_ENV.services.router.host=http://$APP_HOST,$SDK_BUILD.envSdkUrl=http://$SDK_WEB_HOST,$SDK_BUILD.envBackendUrl=http://$APP_HOST" -n hyperswitch -f values.yaml
HYPERLOADER="http://$SDK_URL/0.27.2/v0/HyperLoader.js"
helm upgrade --install hypers-v1 hs/hyperswitch-stack --set "$SDK_ENV.router.host=http://$APP_HOST,$SDK_ENV.sdkDemo.hyperswitchPublishableKey=$PUB_KEY,$SDK_ENV.sdkDemo.hyperswitchSecretKey=$API_KEY,$APP_ENV.services.sdk.host=http://$SDK_URL,$APP_ENV.services.router.host=http://$APP_HOST,$SDK_BUILD.envSdkUrl=http://$SDK_URL,$SDK_BUILD.envBackendUrl=http://$APP_HOST" -n hyperswitch -f values.yaml
echoLog "--------------------------------------------------------------------------------"
echoLog "$bold Service Host$reset"
echoLog "--------------------------------------------------------------------------------"
Expand Down