From faa65d5a4b677c0438fc3c70c839e69455f24053 Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Thu, 23 Jan 2025 10:24:23 -0800 Subject: [PATCH 01/11] initial(draft) --- resources/aws/cloudformation/README.md | 378 ++++++ resources/aws/cloudformation/bastion-eks.yaml | 143 ++ .../eks-helm/cluster-issuer.yaml | 14 + .../cloudformation/eks-helm/helm-values.yaml | 239 ++++ .../cloudformation/eks-helm/sdp-secrets.yaml | 84 ++ .../aws/cloudformation/eks-helm/values.yaml | 239 ++++ .../parameters-database-ecs.json | 42 + .../parameters-database-eks.json | 42 + .../aws/cloudformation/parameters-ecs.json | 26 + .../aws/cloudformation/parameters-eks.json | 26 + .../aws/cloudformation/parameters-keys.json | 34 + .../parameters-network-ecs.json | 14 + .../parameters-network-eks.json | 10 + .../aws/cloudformation/sdp-database-ecs.yaml | 285 ++++ .../aws/cloudformation/sdp-database-eks.yaml | 279 ++++ resources/aws/cloudformation/sdp-ecs.yaml | 1176 +++++++++++++++++ resources/aws/cloudformation/sdp-eks.yaml | 538 ++++++++ resources/aws/cloudformation/sdp-keys.yaml | 491 +++++++ .../aws/cloudformation/sdp-network-ecs.yaml | 411 ++++++ .../aws/cloudformation/sdp-network-eks.yaml | 297 +++++ 20 files changed, 4768 insertions(+) create mode 100644 resources/aws/cloudformation/README.md create mode 100644 resources/aws/cloudformation/bastion-eks.yaml create mode 100644 resources/aws/cloudformation/eks-helm/cluster-issuer.yaml create mode 100644 resources/aws/cloudformation/eks-helm/helm-values.yaml create mode 100644 resources/aws/cloudformation/eks-helm/sdp-secrets.yaml create mode 100644 resources/aws/cloudformation/eks-helm/values.yaml create mode 100644 resources/aws/cloudformation/parameters-database-ecs.json create mode 100644 resources/aws/cloudformation/parameters-database-eks.json create mode 100644 resources/aws/cloudformation/parameters-ecs.json create mode 100644 resources/aws/cloudformation/parameters-eks.json create mode 100644 resources/aws/cloudformation/parameters-keys.json create mode 100644 resources/aws/cloudformation/parameters-network-ecs.json create mode 100644 resources/aws/cloudformation/parameters-network-eks.json create mode 100644 resources/aws/cloudformation/sdp-database-ecs.yaml create mode 100644 resources/aws/cloudformation/sdp-database-eks.yaml create mode 100644 resources/aws/cloudformation/sdp-ecs.yaml create mode 100644 resources/aws/cloudformation/sdp-eks.yaml create mode 100644 resources/aws/cloudformation/sdp-keys.yaml create mode 100644 resources/aws/cloudformation/sdp-network-ecs.yaml create mode 100644 resources/aws/cloudformation/sdp-network-eks.yaml diff --git a/resources/aws/cloudformation/README.md b/resources/aws/cloudformation/README.md new file mode 100644 index 000000000..d91efd07a --- /dev/null +++ b/resources/aws/cloudformation/README.md @@ -0,0 +1,378 @@ +# # Stellar Disbursement Platform (SDP) Kubernetes Deployment Guide + +## Prerequisites +- AWS CLI installed and configured +- Helm installed +- kubectl configured to connect to your cluster + +## Cloudformation Stacks +This guide walks through deploying the Stellar Disbursement Platform (SDP) infrastructure on AWS. The deployment consists of four CloudFormation stacks that create the necessary infrastructure in a specific order: + +- Network Stack (sdp-network-eks.yaml) + - Creates or uses existing VPC and subnets Sets up networking for both public and private resources. Exports used (imported) by database and EKS stack to deploy resources. +- Database Stack (sdp-database-eks.yaml) + - Deploys RDS PostgreSQL database in private subnet + - creates necessary database secrets in AWS Secrets Manager +- Keys Stack (sdp-keys.yaml) + - Manages Stellar keys and encryption secrets + - Provide keys as parameters or leave blank to auto-generate + - Stores all secrets in AWS Secrets Manager +- EKS Stack (sdp-eks.yaml) + - Creates EKS cluster and node group + - Sets up IAM roles and security groups + - Configures necessary permissions for Kubernetes services +After the CloudFormation stacks are deployed, additional Kubernetes resources are installed via Helm charts to complete the setup. + +##Verify AWS CLI Configuration +```bash +aws configure list +aws sts get-caller-identity +``` + +## 1. Network Stack Deployment +Deploy the networking infrastructure: + +```bash +aws cloudformation create-stack \ + --stack-name sdp-network \ + --template-body file://sdp-network-eks.yaml \ + --parameters \ + ParameterKey=env,ParameterValue=dev \ + ParameterKey=AWSRegion,ParameterValue=us-west-2 \ + ParameterKey=ExistingVPCId,ParameterValue="" \ + ParameterKey=VPCCidr,ParameterValue="10.0.0.0/16" +``` + +**Note**: To use existing network resources, provide the VPC and subnet IDs: +```bash +aws cloudformation create-stack \ + --stack-name sdp-network \ + --template-body file://sdp-network-eks.yaml \ + --parameters \ + ParameterKey=env,ParameterValue=dev \ + ParameterKey=ExistingVPCId,ParameterValue=vpc-1234567890abcdef0 \ + ParameterKey=ExistingPublicSubnet1Id,ParameterValue=subnet-xxxxx \ + ParameterKey=ExistingPublicSubnet2Id,ParameterValue=subnet-yyyyy \ + ParameterKey=ExistingPrivateSubnet1Id,ParameterValue=subnet-aaaaa \ + ParameterKey=ExistingPrivateSubnet2Id,ParameterValue=subnet-bbbbb +``` + +Wait for stack completion: +```bash +aws cloudformation wait stack-create-complete --stack-name sdp-network +``` + +## 2. Database Stack Deployment +Deploy the RDS database: + +```bash +aws cloudformation create-stack \ + --stack-name sdp-database \ + --template-body file://sdp-database-eks.yaml \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameters \ + ParameterKey=env,ParameterValue=dev \ + ParameterKey=NetworkStackName,ParameterValue=sdp-network \ + ParameterKey=DBInstanceClass,ParameterValue=db.t3.small \ + ParameterKey=DBUsername,ParameterValue=postgres \ + ParameterKey=DBPassword,ParameterValue=your-secure-password \ + ParameterKey=MultiAZ,ParameterValue=false +``` + +Wait for stack completion: +```bash +aws cloudformation wait stack-create-complete --stack-name sdp-database +``` + +## 3. Keys Stack Deployment +Deploy the secrets and keys management stack: + +```bash +aws cloudformation create-stack \ + --stack-name sdp-keys \ + --template-body file://sdp-keys.yaml \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameters \ + ParameterKey=env,ParameterValue=dev \ + ParameterKey=namespace,ParameterValue=sdp +``` + +**Note**: Leave the following parameters empty to auto-generate new keys: +- DistributionSeed +- DistributionPublicKey +- SEP10SigningPrivateKey +- SEP10SigningPublicKey +- ChannelAccountEncryptionPassphrase +- DistributionAccountEncryptionPassphrase + +Wait for stack completion: +```bash +aws cloudformation wait stack-create-complete --stack-name sdp-keys +``` + +## 4. EKS Cluster Deployment +Deploy the EKS cluster: + +```bash +aws cloudformation create-stack \ + --stack-name sdp-eks \ + --template-body file://sdp-eks.yaml \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameters \ + ParameterKey=env,ParameterValue=dev \ + ParameterKey=NetworkStackName,ParameterValue=sdp-network \ + ParameterKey=DatabaseStackName,ParameterValue=sdp-database \ + ParameterKey=KeysStackName,ParameterValue=sdp-keys +``` + +Wait for stack completion (this will take ~15-20 minutes): +```bash +aws cloudformation wait stack-create-complete --stack-name sdp-eks +``` + +## 5. Configure kubectl +After the EKS cluster is created, configure kubectl: + +```bash +aws eks update-kubeconfig --name $(aws cloudformation describe-stacks \ + --stack-name sdp-eks \ + --query 'Stacks[0].Outputs[?OutputKey==`ClusterName`].OutputValue' \ + --output text) \ + --region your-region +``` + +## 6. Follow Manual Helm Deployment Steps +Continue with the manual Helm deployment steps as provided in the deployment guide, which includes: +1. External Secrets Operator installation +2. AWS Secrets Manager access configuration +3. External Secrets creation +4. Nginx Ingress Controller installation +5. Cert-Manager installation +6. External-DNS setup +7. SDP Helm chart deployment + +Refer to the Helm deployment instructions for these steps. + +## Verification Steps + +### Check Network Stack +```bash +aws cloudformation describe-stacks --stack-name sdp-network \ + --query 'Stacks[0].Outputs' +``` + +### Check Database Connectivity +```bash +aws cloudformation describe-stacks --stack-name sdp-database \ + --query 'Stacks[0].Outputs' +``` + +### Verify EKS Cluster +```bash +aws eks describe-cluster \ + --name $(aws cloudformation describe-stacks \ + --stack-name sdp-eks \ + --query 'Stacks[0].Outputs[?OutputKey==`ClusterName`].OutputValue' \ + --output text) +``` + +### Check Secrets in Secrets Manager +```bash +aws secretsmanager list-secrets \ + --filters Key=name-prefix,Values=/sdp/dev +``` + + +## Initial Setup +```bash +# Configure kubectl for your cluster +aws eks update-kubeconfig --name $(aws cloudformation describe-stacks \ + --stack-name sdp-eks \ + --query 'Stacks[0].Outputs[?OutputKey==`ClusterName`].OutputValue' \ + --output text) + +# Create namespace +kubectl create namespace sdp +``` + +## 1. External Secrets Operator Installation +```bash +# Create external-secrets namespace +kubectl create namespace external-secrets + +# Add and update Helm repository +helm repo add external-secrets https://charts.external-secrets.io +helm repo update + +# Install External Secrets Operator +helm install external-secrets external-secrets/external-secrets \ + --namespace external-secrets \ + --create-namespace \ + --set installCRDs=true \ + --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=$(aws cloudformation describe-stacks \ + --stack-name sdp-eks \ + --query 'Stacks[0].Outputs[?OutputKey==`ExternalSecretsOperatorRoleArn`].OutputValue' \ + --output text) + +# Verify installation +kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=external-secrets -n external-secrets --timeout=120s +``` + +## 2. Configure AWS Secrets Manager Access +```bash +# Set role ARN +export SECRETSTORE_ROLE_ARN=$(aws cloudformation describe-stacks \ + --stack-name sdp-eks \ + --query 'Stacks[0].Outputs[?OutputKey==`SecretStoreRoleArn`].OutputValue' \ + --output text) + +# Create ServiceAccount and SecretStore +cat < + +# Check pod details +kubectl describe pods -n sdp +``` diff --git a/resources/aws/cloudformation/bastion-eks.yaml b/resources/aws/cloudformation/bastion-eks.yaml new file mode 100644 index 000000000..48013b217 --- /dev/null +++ b/resources/aws/cloudformation/bastion-eks.yaml @@ -0,0 +1,143 @@ +Parameters: + env: + Type: String + Default: "dev" + AllowedValues: + - dev + - staging + - prod + + KeyName: + Type: AWS::EC2::KeyPair::KeyName + Description: Name of an existing EC2 KeyPair for SSH access + + NetworkStackName: + Type: String + Default: "sdp-network" + Description: Name of the network stack containing VPC and subnet exports + + DatabaseStackName: + Type: String + Default: "sdp-database" + Description: Name of the database stack containing RDS endpoint and credentials + + EksStackName: + Type: String + Default: "sdp-eks" + Description: Name of the EKS stack containing cluster and service exports + +Resources: + BastionSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for database bastion host + VpcId: !ImportValue + Fn::Sub: ${NetworkStackName}-vpc-id + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 22 + ToPort: 22 + CidrIp: 0.0.0.0/0 + Description: "Allow SSH inbound" + - IpProtocol: tcp + FromPort: 2345 + ToPort: 2345 + CidrIp: 0.0.0.0/0 + Description: "Allow Delve debugger connections" + SecurityGroupEgress: + - IpProtocol: -1 + FromPort: -1 + ToPort: -1 + CidrIp: 0.0.0.0/0 + Tags: + - Key: Name + Value: !Sub ${env}-db-bastion-sg + - Key: env + Value: !Ref env + + BastionHost: + Type: AWS::EC2::Instance + DependsOn: BastionSecurityGroup + Properties: + InstanceType: t2.micro + ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}' + KeyName: !Ref KeyName + SubnetId: !ImportValue + Fn::Sub: ${NetworkStackName}-public-subnet-1 + SecurityGroupIds: + - !Ref BastionSecurityGroup + UserData: + Fn::Base64: | + #!/bin/bash + dnf update -y + dnf install -y postgresql15 + dnf install -y curl jq + Tags: + - Key: Name + Value: !Sub ${env}-db-bastion + - Key: env + Value: !Ref env + + RDSIngressRule: + Type: AWS::EC2::SecurityGroupIngress + DependsOn: BastionSecurityGroup + Properties: + GroupId: !ImportValue + Fn::Sub: ${DatabaseStackName}-db-sg + IpProtocol: tcp + FromPort: 5432 + ToPort: 5432 + SourceSecurityGroupId: !Ref BastionSecurityGroup + Description: "Allow PostgreSQL from Bastion Host" + + EksClusterIngressRule: + Type: AWS::EC2::SecurityGroupIngress + DependsOn: BastionSecurityGroup + Properties: + GroupId: !ImportValue + Fn::Sub: ${EksStackName}-cluster-sg + IpProtocol: tcp + FromPort: 443 + ToPort: 443 + SourceSecurityGroupId: !Ref BastionSecurityGroup + Description: "Allow HTTPS access to EKS cluster from Bastion Host" + +Outputs: + BastionPublicIP: + Description: Public IP of the Bastion Host + Value: !GetAtt BastionHost.PublicIp + + SSHCommand: + Description: Command to SSH to bastion host + Value: !Sub "ssh -i ${KeyName}.pem ec2-user@${BastionHost.PublicIp}" + + DatabaseTunnelCommand: + Description: Command to create SSH tunnel for PostgreSQL + Value: !Sub + - "ssh -N -L 5432:${dbEndpoint}:5432 -i ${KeyName}.pem ec2-user@${BastionHost.PublicIp}" + - dbEndpoint: !ImportValue + Fn::Sub: ${DatabaseStackName}-db-endpoint + + PSQLCommand: + Description: PSQL connection command (after tunnel is established) + Value: !Sub + - "psql -h localhost -U ${dbuser} -d ${dbname}" + - dbuser: !ImportValue + Fn::Sub: ${DatabaseStackName}-dbusername + dbname: !ImportValue + Fn::Sub: ${DatabaseStackName}-db-name + + TenantApiCommand: + Description: Command to access tenant API through local port forwarding + Value: !Sub + - | + # First establish port forwarding + kubectl port-forward pod/sdp 8003:8003 + + # Then in another terminal, use the API + curl -X POST http://localhost:8003/tenants/ \ + -H "Content-Type: application/json" \ + -H "Authorization: Basic $(echo -n 'admin:api_key_1234567890' | base64)" \ + -d '{"name": "acmeorg", "owner_email": "john@stellar.org", "owner_first_name": "john", "owner_last_name": "doe", "organization_name": "acmeorg"}' + - podName: !ImportValue + Fn::Sub: ${EksStackName}-sdp-pod-name \ No newline at end of file diff --git a/resources/aws/cloudformation/eks-helm/cluster-issuer.yaml b/resources/aws/cloudformation/eks-helm/cluster-issuer.yaml new file mode 100644 index 000000000..956c3bed0 --- /dev/null +++ b/resources/aws/cloudformation/eks-helm/cluster-issuer.yaml @@ -0,0 +1,14 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: reece@stellar.org + privateKeySecretRef: + name: letsencrypt-prod + solvers: + - dns01: + route53: + region: us-west-2 \ No newline at end of file diff --git a/resources/aws/cloudformation/eks-helm/helm-values.yaml b/resources/aws/cloudformation/eks-helm/helm-values.yaml new file mode 100644 index 000000000..eda190c8f --- /dev/null +++ b/resources/aws/cloudformation/eks-helm/helm-values.yaml @@ -0,0 +1,239 @@ +global: + isPubnet: false + ephemeralDatabase: false + eventBroker: + type: "NONE" + urls: "kafka:9092" + consumerGroupId: "group-id" + +sdp: + route: + domain: sdp-backend.mystellarsdpdomain.org + mtnDomain: "*.sdp-backend.mystellarsdpdomain.org" + deployment: + podAnnotations: + prometheus.io/path: /metrics + prometheus.io/port: '{{ include "sdp.metricsPort" . }}' + prometheus.io/scrape: "true" + strategy: + # Ensure we upgrade 1 pod at a time to avoid migration races + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + serviceAccount: + create: true + name: sdp-service-account + annotations: + eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} + # =========================== START sdp.kubeSecrets =========================== + kubeSecrets: + secretName: sdp-secrets + create: false + data: + EC256_PRIVATE_KEY: "{{ .Release.Namespace }}/EC256_PRIVATE_KEY" + EC256_PUBLIC_KEY: "{{ .Release.Namespace }}/EC256_PUBLIC_KEY" + SEP10_SIGNING_PRIVATE_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" + SEP10_SIGNING_PUBLIC_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PUBLIC_KEY" + DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" + DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/channel-encryption-passphrase" + DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" + # =========================== START sdp.configMap =========================== + configMap: + data: + ADMIN_ACCOUNT: "reece@stellar.org" + ENVIRONMENT: "dev" + LOG_LEVEL: "debug" + METRICS_TYPE: "PROMETHEUS" + EMAIL_SENDER_TYPE: "DRY_RUN" + SMS_SENDER_TYPE: "DRY_RUN" + ENABLE_MFA: "false" + NETWORK_PASSPHRASE: "Test SDF Network ; September 2015" + HORIZON_URL: "https://horizon-testnet.stellar.org" + INSTANCE_NAME: "Stellar Disbursement Platform" + CORS_ALLOWED_ORIGINS: "*" + ENABLE_SCHEDULER: "true" + SCHEDULER_RECEIVER_INVITATION_JOB_SECONDS: "10" + SCHEDULER_PAYMENT_JOB_SECONDS: "10" + SDP_UI_BASE_URL: "https://dashboard.mystellarsdpdomain.org" + # =========================== START sdp.ingress =========================== + ingress: + enabled: true + className: "ingress-public" + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + tls: + - hosts: + - 'sdp-backend.mystellarsdpdomain.org' + - '*.sdp-backend.mystellarsdpdomain.org' + secretName: sdp-backend-cert +# ============================= anchorPlatform =================================== +anchorPlatform: + route: + domain: ap-sdp-backend.mystellarsdpdomain.org + deployment: + podAnnotations: + prometheus.io/path: /metrics + prometheus.io/port: '{{ include "sdp.ap.metricsPort" . }}' + prometheus.io/scrape: "true" + strategy: + # Ensure we upgrade 1 pod at a time to avoid migration races + type: "RollingUpdate" + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + kubeSecrets: + create: false + secretName: sdp-secrets + data: + SECRET_DATA_USERNAME: "{{ .Release.Namespace }}/SECRET_DATA_USERNAME" + SECRET_DATA_PASSWORD: "{{ .Release.Namespace }}/SECRET_DATA_PASSWORD" + DATA_SERVER: "{{ .Release.Namespace }}/DATA_SERVER" + SECRET_SEP10_SIGNING_SEED: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" + SECRET_PLATFORM_API_AUTH_SECRET: "{{ .Release.Namespace }}/SECRET_PLATFORM_API_AUTH_SECRET" + SECRET_SEP10_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP10_JWT_SECRET" + SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" + SECRET_SEP24_MORE_INFO_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" + DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" + serviceAccount: + create: true + name: anchor-service-account + annotations: + eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} + configMap: + data: + HOST_URL: https://ap-sdp-backend.mystellarsdpdomain.org + SEP_SERVER_PORT: "8080" + CALLBACK_API_BASE_URL: https://sdp-backend.mystellarsdpdomain.org + CALLBACK_API_AUTH_TYPE: "none" + PLATFORM_SERVER_AUTH_TYPE: "JWT" + APP_LOGGING_LEVEL: "INFO" + DATA_TYPE: "postgres" + DATA_DATABASE: "sdp_dev" + DATA_FLYWAY_ENABLED: "true" + DATA_DDL_AUTO: "update" + METRICS_ENABLED: "false" + METRICS_EXTRAS_ENABLED: "false" + EVENT_BROKER_TYPE: "NONE" + SEP10_ENABLED: "true" + SEP10_WEB_AUTH_DOMAIN: ap-sdp-backend.mystellarsdpdomain.org + SEP10_HOME_DOMAINS: "*.sdp-backend.mystellarsdpdomain.org" + SEP24_ENABLED: "true" + SEP24_INTERACTIVE_URL_BASE_URL: https://sdp-backend.mystellarsdpdomain.org/wallet-registration/start + SEP24_INTERACTIVE_URL_JWT_EXPIRATION: "1800" + SEP24_MORE_INFO_URL_BASE_URL: https://sdp-backend.mystellarsdpdomain.org/wallet-registration/start + SEP1_ENABLED: "true" + SEP1_TOML_TYPE: "url" + SEP1_TOML_VALUE: https://sdp-backend.mystellarsdpdomain.org/.well-known/stellar.toml + ASSETS_TYPE: "json" + ASSETS_VALUE: | + { + "assets": [ + { + "sep24_enabled": true, + "schema": "stellar", + "code": "USDC", + "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + "distribution_account": "GCIA55CO7M7VJNDMQYEJKP4WQRB45CL2RJYPDW64PD2X7VDOZS53A4KK", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + }, + { + "sep24_enabled": true, + "schema": "stellar", + "code": "XLM", + "distribution_account": "${DISTRIBUTION_PUBLIC_KEY}", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + } + ] + } + ingress: + enabled: true + className: "ingress-public" + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + tls: + - hosts: + - 'ap-sdp-backend.mystellarsdpdomain.org' + secretName: sdp-ap-cert + +# ============================= tss =================================== +tss: + deployment: + podAnnotations: + prometheus.io/path: /metrics + prometheus.io/port: '{{ include "tss.metricsPort" . }}' + prometheus.io/scrape: "true" + strategy: + type: "RollingUpdate" + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + kubeSecrets: + create: false + secretName: sdp-secrets + data: + DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" + DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" + serviceAccount: + create: true + name: tss-service-account + annotations: + eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} + configMap: + data: + LOG_LEVEL: "info" + NETWORK_PASSPHRASE: "Test SDF Network ; September 2015" + HORIZON_URL: "https://horizon-testnet.stellar.org" + NUM_CHANNEL_ACCOUNTS: "3" + MAX_BASE_FEE: "100" + TSS_METRICS_PORT: "9002" + TSS_METRICS_TYPE: "TSS_PROMETHEUS" + EVENT_BROKER_TYPE: "NONE" + BROKER_URLS: "kafka:9092" + CONSUMER_GROUP_ID: "group-id" + KAFKA_SECURITY_PROTOCOL: "PLAINTEXT" +# ============================= dashboard =================================== +dashboard: + enabled: true + route: + domain: "dashboard.mystellarsdpdomain.org" + mtnDomain: "*.dashboard.mystellarsdpdomain.org" + deployment: + strategy: + type: "RollingUpdate" + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 + configMap: + data: + RECAPTCHA_SITE_KEY: "6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb" + ingress: + enabled: true + className: "ingress-public" + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + tls: + - hosts: + - 'dashboard.mystellarsdpdomain.org' + - '*.dashboard.mystellarsdpdomain.org' + secretName: sdp-dashboard-cert diff --git a/resources/aws/cloudformation/eks-helm/sdp-secrets.yaml b/resources/aws/cloudformation/eks-helm/sdp-secrets.yaml new file mode 100644 index 000000000..fdb27c0ff --- /dev/null +++ b/resources/aws/cloudformation/eks-helm/sdp-secrets.yaml @@ -0,0 +1,84 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: sdp-secrets + namespace: sdp +spec: + refreshInterval: 1h + secretStoreRef: + name: aws-backend + kind: SecretStore + target: + name: sdp-secrets + creationPolicy: Owner + data: + - secretKey: SECRET_DATA_USERNAME + remoteRef: + key: /sdp/SECRET_DATA_USERNAME + - secretKey: SECRET_DATA_PASSWORD + remoteRef: + key: /sdp/SECRET_DATA_PASSWORD + - secretKey: DATA_SERVER + remoteRef: + key: /sdp/DATA_SERVER + - secretKey: DISTRIBUTION_SEED + remoteRef: + key: /sdp/DISTRIBUTION_SEED + - secretKey: DISTRIBUTION_PUBLIC_KEY + remoteRef: + key: /sdp/DISTRIBUTION_PUBLIC_KEY + - secretKey: SEP10_SIGNING_PRIVATE_KEY + remoteRef: + key: /sdp/SEP10_SIGNING_PRIVATE_KEY + - secretKey: SEP10_SIGNING_PUBLIC_KEY + remoteRef: + key: /sdp/SEP10_SIGNING_PUBLIC_KEY + - secretKey: SECRET_SEP10_SIGNING_SEED + remoteRef: + key: /sdp/SECRET_SEP10_SIGNING_SEED + - secretKey: EC256_PRIVATE_KEY + remoteRef: + key: /sdp/EC256_PRIVATE_KEY + - secretKey: EC256_PUBLIC_KEY + remoteRef: + key: /sdp/EC256_PUBLIC_KEY + - secretKey: CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE + remoteRef: + key: /sdp/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE + - secretKey: DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE + remoteRef: + key: /sdp/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE + - secretKey: SECRET_PLATFORM_API_AUTH_SECRET + remoteRef: + key: /sdp/SECRET_PLATFORM_API_AUTH_SECRET + - secretKey: SECRET_SEP10_JWT_SECRET + remoteRef: + key: /sdp/SECRET_SEP10_JWT_SECRET + - secretKey: SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET + remoteRef: + key: /sdp/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET + - secretKey: SECRET_SEP24_MORE_INFO_URL_JWT_SECRET + remoteRef: + key: /sdp/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET + - secretKey: DATABASE_URL + remoteRef: + key: /sdp/DATABASE_URL + - secretKey: SEP24_JWT_SECRET + remoteRef: + key: /sdp/SEP24_JWT_SECRET + - secretKey: ANCHOR_PLATFORM_OUTGOING_JWT_SECRET + remoteRef: + key: /sdp/ANCHOR_PLATFORM_OUTGOING_JWT_SECRET + - secretKey: RECAPTCHA_SITE_KEY + remoteRef: + key: /sdp/RECAPTCHA_SITE_KEY + - secretKey: RECAPTCHA_SITE_SECRET_KEY + remoteRef: + key: /sdp/RECAPTCHA_SITE_SECRET_KEY + - secretKey: ADMIN_API_KEY + remoteRef: + key: /sdp/ADMIN_API_KEY + + + + \ No newline at end of file diff --git a/resources/aws/cloudformation/eks-helm/values.yaml b/resources/aws/cloudformation/eks-helm/values.yaml new file mode 100644 index 000000000..eda190c8f --- /dev/null +++ b/resources/aws/cloudformation/eks-helm/values.yaml @@ -0,0 +1,239 @@ +global: + isPubnet: false + ephemeralDatabase: false + eventBroker: + type: "NONE" + urls: "kafka:9092" + consumerGroupId: "group-id" + +sdp: + route: + domain: sdp-backend.mystellarsdpdomain.org + mtnDomain: "*.sdp-backend.mystellarsdpdomain.org" + deployment: + podAnnotations: + prometheus.io/path: /metrics + prometheus.io/port: '{{ include "sdp.metricsPort" . }}' + prometheus.io/scrape: "true" + strategy: + # Ensure we upgrade 1 pod at a time to avoid migration races + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + serviceAccount: + create: true + name: sdp-service-account + annotations: + eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} + # =========================== START sdp.kubeSecrets =========================== + kubeSecrets: + secretName: sdp-secrets + create: false + data: + EC256_PRIVATE_KEY: "{{ .Release.Namespace }}/EC256_PRIVATE_KEY" + EC256_PUBLIC_KEY: "{{ .Release.Namespace }}/EC256_PUBLIC_KEY" + SEP10_SIGNING_PRIVATE_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" + SEP10_SIGNING_PUBLIC_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PUBLIC_KEY" + DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" + DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/channel-encryption-passphrase" + DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" + # =========================== START sdp.configMap =========================== + configMap: + data: + ADMIN_ACCOUNT: "reece@stellar.org" + ENVIRONMENT: "dev" + LOG_LEVEL: "debug" + METRICS_TYPE: "PROMETHEUS" + EMAIL_SENDER_TYPE: "DRY_RUN" + SMS_SENDER_TYPE: "DRY_RUN" + ENABLE_MFA: "false" + NETWORK_PASSPHRASE: "Test SDF Network ; September 2015" + HORIZON_URL: "https://horizon-testnet.stellar.org" + INSTANCE_NAME: "Stellar Disbursement Platform" + CORS_ALLOWED_ORIGINS: "*" + ENABLE_SCHEDULER: "true" + SCHEDULER_RECEIVER_INVITATION_JOB_SECONDS: "10" + SCHEDULER_PAYMENT_JOB_SECONDS: "10" + SDP_UI_BASE_URL: "https://dashboard.mystellarsdpdomain.org" + # =========================== START sdp.ingress =========================== + ingress: + enabled: true + className: "ingress-public" + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + tls: + - hosts: + - 'sdp-backend.mystellarsdpdomain.org' + - '*.sdp-backend.mystellarsdpdomain.org' + secretName: sdp-backend-cert +# ============================= anchorPlatform =================================== +anchorPlatform: + route: + domain: ap-sdp-backend.mystellarsdpdomain.org + deployment: + podAnnotations: + prometheus.io/path: /metrics + prometheus.io/port: '{{ include "sdp.ap.metricsPort" . }}' + prometheus.io/scrape: "true" + strategy: + # Ensure we upgrade 1 pod at a time to avoid migration races + type: "RollingUpdate" + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + kubeSecrets: + create: false + secretName: sdp-secrets + data: + SECRET_DATA_USERNAME: "{{ .Release.Namespace }}/SECRET_DATA_USERNAME" + SECRET_DATA_PASSWORD: "{{ .Release.Namespace }}/SECRET_DATA_PASSWORD" + DATA_SERVER: "{{ .Release.Namespace }}/DATA_SERVER" + SECRET_SEP10_SIGNING_SEED: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" + SECRET_PLATFORM_API_AUTH_SECRET: "{{ .Release.Namespace }}/SECRET_PLATFORM_API_AUTH_SECRET" + SECRET_SEP10_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP10_JWT_SECRET" + SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" + SECRET_SEP24_MORE_INFO_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" + DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" + serviceAccount: + create: true + name: anchor-service-account + annotations: + eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} + configMap: + data: + HOST_URL: https://ap-sdp-backend.mystellarsdpdomain.org + SEP_SERVER_PORT: "8080" + CALLBACK_API_BASE_URL: https://sdp-backend.mystellarsdpdomain.org + CALLBACK_API_AUTH_TYPE: "none" + PLATFORM_SERVER_AUTH_TYPE: "JWT" + APP_LOGGING_LEVEL: "INFO" + DATA_TYPE: "postgres" + DATA_DATABASE: "sdp_dev" + DATA_FLYWAY_ENABLED: "true" + DATA_DDL_AUTO: "update" + METRICS_ENABLED: "false" + METRICS_EXTRAS_ENABLED: "false" + EVENT_BROKER_TYPE: "NONE" + SEP10_ENABLED: "true" + SEP10_WEB_AUTH_DOMAIN: ap-sdp-backend.mystellarsdpdomain.org + SEP10_HOME_DOMAINS: "*.sdp-backend.mystellarsdpdomain.org" + SEP24_ENABLED: "true" + SEP24_INTERACTIVE_URL_BASE_URL: https://sdp-backend.mystellarsdpdomain.org/wallet-registration/start + SEP24_INTERACTIVE_URL_JWT_EXPIRATION: "1800" + SEP24_MORE_INFO_URL_BASE_URL: https://sdp-backend.mystellarsdpdomain.org/wallet-registration/start + SEP1_ENABLED: "true" + SEP1_TOML_TYPE: "url" + SEP1_TOML_VALUE: https://sdp-backend.mystellarsdpdomain.org/.well-known/stellar.toml + ASSETS_TYPE: "json" + ASSETS_VALUE: | + { + "assets": [ + { + "sep24_enabled": true, + "schema": "stellar", + "code": "USDC", + "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + "distribution_account": "GCIA55CO7M7VJNDMQYEJKP4WQRB45CL2RJYPDW64PD2X7VDOZS53A4KK", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + }, + { + "sep24_enabled": true, + "schema": "stellar", + "code": "XLM", + "distribution_account": "${DISTRIBUTION_PUBLIC_KEY}", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + } + ] + } + ingress: + enabled: true + className: "ingress-public" + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + tls: + - hosts: + - 'ap-sdp-backend.mystellarsdpdomain.org' + secretName: sdp-ap-cert + +# ============================= tss =================================== +tss: + deployment: + podAnnotations: + prometheus.io/path: /metrics + prometheus.io/port: '{{ include "tss.metricsPort" . }}' + prometheus.io/scrape: "true" + strategy: + type: "RollingUpdate" + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + kubeSecrets: + create: false + secretName: sdp-secrets + data: + DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" + DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" + serviceAccount: + create: true + name: tss-service-account + annotations: + eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} + configMap: + data: + LOG_LEVEL: "info" + NETWORK_PASSPHRASE: "Test SDF Network ; September 2015" + HORIZON_URL: "https://horizon-testnet.stellar.org" + NUM_CHANNEL_ACCOUNTS: "3" + MAX_BASE_FEE: "100" + TSS_METRICS_PORT: "9002" + TSS_METRICS_TYPE: "TSS_PROMETHEUS" + EVENT_BROKER_TYPE: "NONE" + BROKER_URLS: "kafka:9092" + CONSUMER_GROUP_ID: "group-id" + KAFKA_SECURITY_PROTOCOL: "PLAINTEXT" +# ============================= dashboard =================================== +dashboard: + enabled: true + route: + domain: "dashboard.mystellarsdpdomain.org" + mtnDomain: "*.dashboard.mystellarsdpdomain.org" + deployment: + strategy: + type: "RollingUpdate" + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 + configMap: + data: + RECAPTCHA_SITE_KEY: "6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb" + ingress: + enabled: true + className: "ingress-public" + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + tls: + - hosts: + - 'dashboard.mystellarsdpdomain.org' + - '*.dashboard.mystellarsdpdomain.org' + secretName: sdp-dashboard-cert diff --git a/resources/aws/cloudformation/parameters-database-ecs.json b/resources/aws/cloudformation/parameters-database-ecs.json new file mode 100644 index 000000000..3145bc743 --- /dev/null +++ b/resources/aws/cloudformation/parameters-database-ecs.json @@ -0,0 +1,42 @@ +[ + { + "ParameterKey": "NetworkStackName", + "ParameterValue": "sdp-network-eks" + }, + { + "ParameterKey": "env", + "ParameterValue": "dev" + }, + { + "ParameterKey": "namespace", + "ParameterValue": "sdp" + }, + { + "ParameterKey": "DBInstanceClass", + "ParameterValue": "db.t3.small" + }, + { + "ParameterKey": "DBAllocatedStorage", + "ParameterValue": "20" + }, + { + "ParameterKey": "DBUsername", + "ParameterValue": "postgres" + }, + { + "ParameterKey": "BackupRetentionPeriod", + "ParameterValue": "7" + }, + { + "ParameterKey": "MultiAZ", + "ParameterValue": "false" + }, + { + "ParameterKey": "DeletionProtection", + "ParameterValue": "false" + }, + { + "ParameterKey": "DBPassword", + "ParameterValue": "postgres" + } +] diff --git a/resources/aws/cloudformation/parameters-database-eks.json b/resources/aws/cloudformation/parameters-database-eks.json new file mode 100644 index 000000000..3145bc743 --- /dev/null +++ b/resources/aws/cloudformation/parameters-database-eks.json @@ -0,0 +1,42 @@ +[ + { + "ParameterKey": "NetworkStackName", + "ParameterValue": "sdp-network-eks" + }, + { + "ParameterKey": "env", + "ParameterValue": "dev" + }, + { + "ParameterKey": "namespace", + "ParameterValue": "sdp" + }, + { + "ParameterKey": "DBInstanceClass", + "ParameterValue": "db.t3.small" + }, + { + "ParameterKey": "DBAllocatedStorage", + "ParameterValue": "20" + }, + { + "ParameterKey": "DBUsername", + "ParameterValue": "postgres" + }, + { + "ParameterKey": "BackupRetentionPeriod", + "ParameterValue": "7" + }, + { + "ParameterKey": "MultiAZ", + "ParameterValue": "false" + }, + { + "ParameterKey": "DeletionProtection", + "ParameterValue": "false" + }, + { + "ParameterKey": "DBPassword", + "ParameterValue": "postgres" + } +] diff --git a/resources/aws/cloudformation/parameters-ecs.json b/resources/aws/cloudformation/parameters-ecs.json new file mode 100644 index 000000000..c1e27814b --- /dev/null +++ b/resources/aws/cloudformation/parameters-ecs.json @@ -0,0 +1,26 @@ +[ + { + "ParameterKey": "FrontendImage", + "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:frontend-3.0.0" + }, + { + "ParameterKey": "BackendImage", + "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:development-amd64" + }, + { + "ParameterKey": "AnchorImage", + "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:anchor-2.6.0" + }, + { + "ParameterKey": "DomainName", + "ParameterValue": "mystellarsdpdomain.org" + }, + { + "ParameterKey": "HostedZoneId", + "ParameterValue": "Z06404593U3HC3DPDLDQK" + }, + { + "ParameterKey": "EmailSenderType", + "ParameterValue": "AWS_EMAIL" + } +] diff --git a/resources/aws/cloudformation/parameters-eks.json b/resources/aws/cloudformation/parameters-eks.json new file mode 100644 index 000000000..c1e27814b --- /dev/null +++ b/resources/aws/cloudformation/parameters-eks.json @@ -0,0 +1,26 @@ +[ + { + "ParameterKey": "FrontendImage", + "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:frontend-3.0.0" + }, + { + "ParameterKey": "BackendImage", + "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:development-amd64" + }, + { + "ParameterKey": "AnchorImage", + "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:anchor-2.6.0" + }, + { + "ParameterKey": "DomainName", + "ParameterValue": "mystellarsdpdomain.org" + }, + { + "ParameterKey": "HostedZoneId", + "ParameterValue": "Z06404593U3HC3DPDLDQK" + }, + { + "ParameterKey": "EmailSenderType", + "ParameterValue": "AWS_EMAIL" + } +] diff --git a/resources/aws/cloudformation/parameters-keys.json b/resources/aws/cloudformation/parameters-keys.json new file mode 100644 index 000000000..3d4680baa --- /dev/null +++ b/resources/aws/cloudformation/parameters-keys.json @@ -0,0 +1,34 @@ +[ + { + "ParameterKey": "EC256PrivateKey", + "ParameterValue": "-----BEGIN EC PRIVATE KEY-----\\nMHcCAQEEIPRRtyc5EQoNPFhkcDzC47B2Zpo5b0NiM3Ftvky86+bEoAoGCCqGSM49\\nAwEHoUQDQgAEWinhVw0QHkZDeZ777zfBKT0cupULkpEd8Y52iPs76AT7JQ1cuGbm\\njxJASNwp907KzNzOZJSV07bFdN/Tkwebgg==\\n-----END EC PRIVATE KEY-----" + }, + { + "ParameterKey": "EC256PublicKey", + "ParameterValue": "-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWinhVw0QHkZDeZ777zfBKT0cupUL\\nkpEd8Y52iPs76AT7JQ1cuGbmjxJASNwp907KzNzOZJSV07bFdN/Tkwebgg==\\n-----END PUBLIC KEY-----" + }, + { + "ParameterKey": "SEP10SigningPrivateKey", + "ParameterValue": "SBTLJ5S6A67SZZPRCIFKXJJO2OMZE5XNKSB7SZYLHWUCQ7XYA5MAOF6M" + }, + { + "ParameterKey": "SEP10SigningPublicKey", + "ParameterValue": "GB3H55YEBHRT7ONUIYYXOXH5JXX4XLXSBIXHWSS2S5AOHPCZBVJH5LYH" + }, + { + "ParameterKey": "DistributionPublicKey", + "ParameterValue": "GCIA55CO7M7VJNDMQYEJKP4WQRB45CL2RJYPDW64PD2X7VDOZS53A4KK" + }, + { + "ParameterKey": "DistributionSeed", + "ParameterValue": "SBOTKS44HJCPKL5VZ5774IZ7ALV4OQEZD4PNCKBVQ522TH6OLNGXSLRI" + }, + { + "ParameterKey": "DistributionAccountEncryptionPassphrase", + "ParameterValue": "SBOTKS44HJCPKL5VZ5774IZ7ALV4OQEZD4PNCKBVQ522TH6OLNGXSLRI" + }, + { + "ParameterKey": "ChannelAccountEncryptionPassphrase", + "ParameterValue": "SBOTKS44HJCPKL5VZ5774IZ7ALV4OQEZD4PNCKBVQ522TH6OLNGXSLRI" + } +] diff --git a/resources/aws/cloudformation/parameters-network-ecs.json b/resources/aws/cloudformation/parameters-network-ecs.json new file mode 100644 index 000000000..49e711109 --- /dev/null +++ b/resources/aws/cloudformation/parameters-network-ecs.json @@ -0,0 +1,14 @@ +[ + { + "ParameterKey": "env", + "ParameterValue": "dev" + }, + { + "ParameterKey": "AWSRegion", + "ParameterValue": "us-west-2" + }, + { + "ParameterKey": "CertificateArn", + "ParameterValue": "arn:aws:acm:us-west-2:245943599471:certificate/ff147acc-5267-4d24-9635-cccd00f658b6" + } +] diff --git a/resources/aws/cloudformation/parameters-network-eks.json b/resources/aws/cloudformation/parameters-network-eks.json new file mode 100644 index 000000000..cb63c08c5 --- /dev/null +++ b/resources/aws/cloudformation/parameters-network-eks.json @@ -0,0 +1,10 @@ +[ + { + "ParameterKey": "env", + "ParameterValue": "prod" + }, + { + "ParameterKey": "AWSRegion", + "ParameterValue": "us-west-2" + } +] diff --git a/resources/aws/cloudformation/sdp-database-ecs.yaml b/resources/aws/cloudformation/sdp-database-ecs.yaml new file mode 100644 index 000000000..22f5d7a9b --- /dev/null +++ b/resources/aws/cloudformation/sdp-database-ecs.yaml @@ -0,0 +1,285 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: RDS Database Stack for SDP + +Parameters: + NetworkStackName: + Type: String + Default: sdp-network + Description: Name of the network stack to import VPC and subnet values from + + env: + Type: String + Default: "dev" + AllowedValues: + - dev + - staging + - prod + Description: Environment name + + namespace: + Type: String + Description: "Kubernetes only. namespace where SDP will be deployed" + Default: "sdp" + + DBInstanceClass: + Type: String + Default: db.t3.small + AllowedValues: + - db.t3.small + - db.t3.medium + - db.t3.large + - db.r5.large + Description: Database instance size + + DBAllocatedStorage: + Type: Number + Default: 20 + MinValue: 20 + MaxValue: 1000 + Description: Size of database storage in GB + + DBUsername: + Type: String + Default: postgres + MinLength: 1 + MaxLength: 16 + AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription: Must begin with a letter and contain only alphanumeric characters + Description: Database admin username + + BackupRetentionPeriod: + Type: Number + Default: 7 + MinValue: 0 + MaxValue: 35 + Description: Number of days to retain automated backups + + MultiAZ: + Type: String + Default: false + AllowedValues: + - true + - false + Description: Enable Multi-AZ deployment + + DeletionProtection: + Type: String + Default: false + AllowedValues: + - true + - false + Description: Enable deletion protection + + DBPassword: + Type: String + Default: postgres + NoEcho: true + MinLength: 8 + Description: Password for database admin user + +Resources: + RDSSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for RDS instance + VpcId: + Fn::ImportValue: !Sub ${NetworkStackName}-vpc-id + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 5432 + ToPort: 5432 + SourceSecurityGroupId: + Fn::ImportValue: !Sub ${NetworkStackName}-ecs-services-sg + SecurityGroupEgress: + - IpProtocol: -1 + FromPort: -1 + ToPort: -1 + CidrIp: 0.0.0.0/0 + Tags: + - Key: Name + Value: !Sub ${env}-rds-security-group + - Key: Environment + Value: !Ref env + + DBSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/credentials + Description: RDS database credentials and connection information + SecretString: !Sub '{"username": "${DBUsername}", "password": "${DBPassword}", "dbname": "sdp_${env}", "port": 5432, "host": "${PostgresInstance.Endpoint.Address}"}' + + DatabaseURLSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/url + Description: Complete database connection URL + SecretString: !Sub '{"DATABASE_URL": "postgres://${DBUsername}:${DBPassword}@${PostgresInstance.Endpoint.Address}:${PostgresInstance.Endpoint.Port}/sdp_${env}"}' + + DatabaseHostSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/host + Description: Database host + SecretString: !GetAtt PostgresInstance.Endpoint.Address + + DatabasePortSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/port + Description: Database port + SecretString: !GetAtt PostgresInstance.Endpoint.Port + + DatabaseNameSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/name + Description: Database name + SecretString: !Sub sdp_${env} + + SecretDataUsernameSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_DATA_USERNAME + Description: Anchor Platform DATA_USER + SecretString: !Ref DBUsername + + SecretDataPasswordSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_DATA_PASSWORD + Description: Anchor Platform SECRET_DATA_PASSWORD + SecretString: !Ref DBPassword + + DataServerSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/DATA_SERVER + Description: Anchor Platform DATA_SERVER + SecretString: !GetAtt PostgresInstance.Endpoint.Address + + DatabaseURLSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/DATABASE_URL + Description: Complete database connection URL + SecretString: !Sub "postgres://${DBUsername}:${DBPassword}@${PostgresInstance.Endpoint.Address}:${PostgresInstance.Endpoint.Port}/sdp_${env}" + + DBSubnetGroup: + Type: AWS::RDS::DBSubnetGroup + Properties: + DBSubnetGroupDescription: !Sub ${env}-database-subnet-group + SubnetIds: + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-1 + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-2 + Tags: + - Key: Name + Value: !Sub ${env}-database-subnet-group + - Key: Environment + Value: !Ref env + + DBParameterGroup: + Type: AWS::RDS::DBParameterGroup + Properties: + Family: postgres14 + Description: Custom parameter group for SDP database + Parameters: + max_connections: "50" + shared_buffers: "4096" + ssl: "1" + Tags: + - Key: Environment + Value: !Ref env + + PostgresInstance: + Type: AWS::RDS::DBInstance + Properties: + DBName: !Sub sdp_${env} + Engine: postgres + EngineVersion: 14 + DBInstanceClass: !Ref DBInstanceClass + AllocatedStorage: !Ref DBAllocatedStorage + StorageType: gp2 + StorageEncrypted: true + MultiAZ: !Ref MultiAZ + PubliclyAccessible: false + DeletionProtection: !Ref DeletionProtection + DBSubnetGroupName: !Ref DBSubnetGroup + VPCSecurityGroups: + - !Ref RDSSecurityGroup + BackupRetentionPeriod: !Ref BackupRetentionPeriod + DBParameterGroupName: !Ref DBParameterGroup + MasterUsername: !Ref DBUsername + MasterUserPassword: !Ref DBPassword + MonitoringInterval: 0 + AutoMinorVersionUpgrade: true + CopyTagsToSnapshot: true + Tags: + - Key: Name + Value: !Sub ${env}-sdp-database + - Key: Environment + Value: !Ref env + + DBEndpointParameter: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub /sdp/${env}/DB_ENDPOINT + Type: String + Value: !GetAtt PostgresInstance.Endpoint.Address + Description: Database endpoint + Tags: + Environment: !Ref env + + DBPortParameter: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub /sdp/${env}/DB_PORT + Type: String + Value: !GetAtt PostgresInstance.Endpoint.Port + Description: Database port + Tags: + Environment: !Ref env + + DBNameParameter: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub /sdp/${env}/DB_NAME + Type: String + Value: !Sub sdp_${env} + Description: Database name + Tags: + Environment: !Ref env + +Outputs: + DatabaseEndpoint: + Description: Database endpoint + Value: !GetAtt PostgresInstance.Endpoint.Address + Export: + Name: !Sub ${AWS::StackName}-db-endpoint + + DatabasePort: + Description: Database port + Value: !GetAtt PostgresInstance.Endpoint.Port + Export: + Name: !Sub ${AWS::StackName}-db-port + + DatabaseName: + Description: Database name + Value: !Sub sdp_${env} + Export: + Name: !Sub ${AWS::StackName}-db-name + + DatabaseSecretArn: + Value: !Ref DBSecret + Export: + Name: !Sub ${AWS::StackName}-db-secret-arn + + DatabaseUrlSecret: + Value: !Ref DatabaseURLSecret + Export: + Name: !Sub ${AWS::StackName}-database-url-secret + + DatabaseSecurityGroup: + Description: Security Group ID for RDS instance + Value: !Ref RDSSecurityGroup + Export: + Name: !Sub ${AWS::StackName}-db-sg \ No newline at end of file diff --git a/resources/aws/cloudformation/sdp-database-eks.yaml b/resources/aws/cloudformation/sdp-database-eks.yaml new file mode 100644 index 000000000..fd14f98e2 --- /dev/null +++ b/resources/aws/cloudformation/sdp-database-eks.yaml @@ -0,0 +1,279 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: RDS Database Stack for SDP on EKS + +Parameters: + NetworkStackName: + Type: String + Default: sdp-network + Description: Name of the network stack to import VPC and subnet values from + + env: + Type: String + Default: "dev" + AllowedValues: + - dev + - staging + - prod + Description: Environment name + + namespace: + Type: String + Description: "Kubernetes namespace where SDP will be deployed" + Default: "sdp" + + DBInstanceClass: + Type: String + Default: db.t3.small + AllowedValues: + - db.t3.small + - db.t3.medium + - db.t3.large + - db.r5.large + Description: Database instance size + + DBAllocatedStorage: + Type: Number + Default: 20 + MinValue: 20 + MaxValue: 1000 + Description: Size of database storage in GB + + DBUsername: + Type: String + Default: postgres + MinLength: 1 + MaxLength: 16 + AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription: Must begin with a letter and contain only alphanumeric characters + Description: Database admin username + + BackupRetentionPeriod: + Type: Number + Default: 7 + MinValue: 0 + MaxValue: 35 + Description: Number of days to retain automated backups + + MultiAZ: + Type: String + Default: false + AllowedValues: + - true + - false + Description: Enable Multi-AZ deployment + + DeletionProtection: + Type: String + Default: false + AllowedValues: + - true + - false + Description: Enable deletion protection + + DBPassword: + Type: String + Default: postgres + NoEcho: true + MinLength: 8 + Description: Password for database admin user + +Resources: + RDSSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for RDS instance + VpcId: + Fn::ImportValue: !Sub ${NetworkStackName}-vpc-id + SecurityGroupEgress: + - IpProtocol: -1 + FromPort: -1 + ToPort: -1 + CidrIp: 0.0.0.0/0 + Tags: + - Key: Name + Value: !Sub ${env}-rds-security-group + - Key: Environment + Value: !Ref env + + DBSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/credentials + Description: RDS database credentials and connection information + SecretString: !Sub '{"username": "${DBUsername}", "password": "${DBPassword}", "dbname": "sdp_${env}", "port": 5432, "host": "${PostgresInstance.Endpoint.Address}"}' + + DatabaseURLSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/url + Description: Complete database connection URL + SecretString: !Sub '{"DATABASE_URL": "postgres://${DBUsername}:${DBPassword}@${PostgresInstance.Endpoint.Address}:${PostgresInstance.Endpoint.Port}/sdp_${env}"}' + + DatabaseHostSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/host + Description: Database host + SecretString: !GetAtt PostgresInstance.Endpoint.Address + + DatabasePortSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/port + Description: Database port + SecretString: !GetAtt PostgresInstance.Endpoint.Port + + DatabaseNameSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/db/name + Description: Database name + SecretString: !Sub sdp_${env} + + SecretDataUsernameSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_DATA_USERNAME + Description: Anchor Platform DATA_USER + SecretString: !Ref DBUsername + + SecretDataPasswordSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_DATA_PASSWORD + Description: Anchor Platform SECRET_DATA_PASSWORD + SecretString: !Ref DBPassword + + DataServerSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/DATA_SERVER + Description: Anchor Platform DATA_SERVER + SecretString: !GetAtt PostgresInstance.Endpoint.Address + + DatabaseURLSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/DATABASE_URL + Description: Complete database connection URL + SecretString: !Sub "postgres://${DBUsername}:${DBPassword}@${PostgresInstance.Endpoint.Address}:${PostgresInstance.Endpoint.Port}/sdp_${env}" + + DBSubnetGroup: + Type: AWS::RDS::DBSubnetGroup + Properties: + DBSubnetGroupDescription: !Sub ${env}-database-subnet-group + SubnetIds: + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-1 + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-2 + Tags: + - Key: Name + Value: !Sub ${env}-database-subnet-group + - Key: Environment + Value: !Ref env + + DBParameterGroup: + Type: AWS::RDS::DBParameterGroup + Properties: + Family: postgres14 + Description: Custom parameter group for SDP database + Parameters: + max_connections: "50" + shared_buffers: "4096" + ssl: "1" + Tags: + - Key: Environment + Value: !Ref env + + PostgresInstance: + Type: AWS::RDS::DBInstance + Properties: + DBName: !Sub sdp_${env} + Engine: postgres + EngineVersion: 14 + DBInstanceClass: !Ref DBInstanceClass + AllocatedStorage: !Ref DBAllocatedStorage + StorageType: gp2 + StorageEncrypted: true + MultiAZ: !Ref MultiAZ + PubliclyAccessible: false + DeletionProtection: !Ref DeletionProtection + DBSubnetGroupName: !Ref DBSubnetGroup + VPCSecurityGroups: + - !Ref RDSSecurityGroup + BackupRetentionPeriod: !Ref BackupRetentionPeriod + DBParameterGroupName: !Ref DBParameterGroup + MasterUsername: !Ref DBUsername + MasterUserPassword: !Ref DBPassword + MonitoringInterval: 0 + AutoMinorVersionUpgrade: true + CopyTagsToSnapshot: true + Tags: + - Key: Name + Value: !Sub ${env}-sdp-database + - Key: Environment + Value: !Ref env + + DBEndpointParameter: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub /sdp/${env}/DB_ENDPOINT + Type: String + Value: !GetAtt PostgresInstance.Endpoint.Address + Description: Database endpoint + Tags: + Environment: !Ref env + + DBPortParameter: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub /sdp/${env}/DB_PORT + Type: String + Value: !GetAtt PostgresInstance.Endpoint.Port + Description: Database port + Tags: + Environment: !Ref env + + DBNameParameter: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub /sdp/${env}/DB_NAME + Type: String + Value: !Sub sdp_${env} + Description: Database name + Tags: + Environment: !Ref env + +Outputs: + DatabaseEndpoint: + Description: Database endpoint + Value: !GetAtt PostgresInstance.Endpoint.Address + Export: + Name: !Sub ${AWS::StackName}-db-endpoint + + DatabasePort: + Description: Database port + Value: !GetAtt PostgresInstance.Endpoint.Port + Export: + Name: !Sub ${AWS::StackName}-db-port + + DatabaseName: + Description: Database name + Value: !Sub sdp_${env} + Export: + Name: !Sub ${AWS::StackName}-db-name + + DatabaseSecretArn: + Value: !Ref DBSecret + Export: + Name: !Sub ${AWS::StackName}-db-secret-arn + + DatabaseUrlSecret: + Value: !Ref DatabaseURLSecret + Export: + Name: !Sub ${AWS::StackName}-database-url-secret + + DatabaseSecurityGroup: + Description: Security Group ID for RDS instance + Value: !Ref RDSSecurityGroup + Export: + Name: !Sub ${AWS::StackName}-db-sg diff --git a/resources/aws/cloudformation/sdp-ecs.yaml b/resources/aws/cloudformation/sdp-ecs.yaml new file mode 100644 index 000000000..f25e4ee7f --- /dev/null +++ b/resources/aws/cloudformation/sdp-ecs.yaml @@ -0,0 +1,1176 @@ + Parameters: + env: + Type: String + Default: "dev" + + DomainName: + Type: String + + HostedZoneId: + Type: String + + FrontendImage: + Type: String + Default: "stellar/stellar-disbursement-platform-frontend:3.0.0" + + BackendImage: + Type: String + + AnchorImage: + Type: String + Default: "stellar/anchor-platform:2.6.0" + + EmailSenderType: + Type: String + Default: "AWS_EMAIL" + AllowedValues: + - AWS_EMAIL + - TWILLIO_EMAIL + - DRY_RUN + + SmsSenderType: + Type: String + Default: "DRY_RUN" + AllowedValues: + - AWS_SMS + - TWILLIO_SMS + - DRY_RUN + + Resources: + AnchorSepListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-https-listener-arn + Priority: 5 + Conditions: + - Field: host-header + Values: + - !Sub "anchor.${DomainName}" + Actions: + - Type: forward + TargetGroupArn: !Ref AnchorSepTargetGroup + + AnchorPlatformListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-private-https-listener-arn + Priority: 6 + Conditions: + - Field: host-header + Values: + - !Sub "anchor-platform.${DomainName}" + Actions: + - Type: forward + TargetGroupArn: !Ref AnchorPlatformTargetGroup + + TenantListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-private-https-listener-arn + Priority: 8 + Conditions: + - Field: host-header + Values: + - !Sub admin.${DomainName} + - Field: path-pattern + Values: + - "/tenants/*" + Actions: + - Type: forward + TargetGroupArn: !Ref TenantTargetGroup + + SDPListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-https-listener-arn + Priority: 10 + Conditions: + - Field: host-header + Values: + - !Sub "sdp-backend.${DomainName}" + Actions: + - Type: forward + TargetGroupArn: !Ref SDPTargetGroup + + WalletRegistrationRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-https-listener-arn + Priority: 25 + Conditions: + - Field: host-header + Values: + - !Sub sdp-backend.${DomainName} + - Field: path-pattern + Values: + - "/wallet-registration/*" + Actions: + - Type: forward + TargetGroupArn: !Ref SDPTargetGroup + + TomlRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-https-listener-arn + Priority: 26 + Conditions: + - Field: host-header + Values: + - !Sub "*.${DomainName}" + - Field: path-pattern + Values: + - "/.well-known/*" + Actions: + - Type: forward + TargetGroupArn: !Ref SDPTargetGroup + + SepListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-https-listener-arn + Priority: 29 + Conditions: + - Field: host-header + Values: + - !Sub "*.${DomainName}" + - Field: path-pattern + Values: + - "/sep24/*" + Actions: + - Type: forward + TargetGroupArn: !Ref AnchorSepTargetGroup + + FrontendListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: + Fn::ImportValue: sdp-network-https-listener-arn + Priority: 40 + Conditions: + - Field: host-header + Values: + - !Sub "*.${DomainName}" + Actions: + - Type: forward + TargetGroupArn: !Ref FrontendTargetGroup + + SDPTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + VpcId: + Fn::ImportValue: sdp-network-vpc-id + Port: 8000 + Protocol: HTTP + TargetType: ip + HealthCheckPath: /health + HealthCheckEnabled: true + HealthCheckIntervalSeconds: 30 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 2 + UnhealthyThresholdCount: 5 + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-sdp-tg + + TenantTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + VpcId: + Fn::ImportValue: sdp-network-vpc-id + Port: 8003 + Protocol: HTTP + TargetType: ip + HealthCheckPath: /health + HealthCheckEnabled: true + HealthCheckIntervalSeconds: 30 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 2 + UnhealthyThresholdCount: 5 + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-tenant-tg + + AnchorPlatformTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + VpcId: + Fn::ImportValue: sdp-network-vpc-id + Port: 8085 + Protocol: HTTP + TargetType: ip + HealthCheckPath: /health?checks=config + HealthCheckEnabled: true + HealthCheckIntervalSeconds: 60 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 2 + UnhealthyThresholdCount: 5 + HealthCheckPort: 8080 + TargetGroupAttributes: + - Key: deregistration_delay.timeout_seconds + Value: '30' + - Key: slow_start.duration_seconds + Value: '60' + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-anchor-platform-tg + + AnchorSepTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + VpcId: + Fn::ImportValue: sdp-network-vpc-id + Port: 8080 + Protocol: HTTP + TargetType: ip + HealthCheckPath: /health?checks=config + HealthCheckEnabled: true + HealthCheckIntervalSeconds: 60 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 2 + UnhealthyThresholdCount: 5 + HealthCheckPort: 8080 + TargetGroupAttributes: + - Key: deregistration_delay.timeout_seconds + Value: '30' + - Key: slow_start.duration_seconds + Value: '60' + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-anchor-sep-tg + + FrontendTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + VpcId: + Fn::ImportValue: sdp-network-vpc-id + Port: 80 + Protocol: HTTP + TargetType: ip + HealthCheckEnabled: true + HealthCheckPath: / + HealthCheckIntervalSeconds: 30 + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 2 + UnhealthyThresholdCount: 5 + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-frontend-tg + + ECSCluster: + Type: AWS::ECS::Cluster + Properties: + ClusterName: !Sub ${env}-${AWS::StackName}-cluster + CapacityProviders: + - FARGATE + DefaultCapacityProviderStrategy: + - CapacityProvider: FARGATE + Weight: 1 + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-cluster + + ECSTaskExecutionRolePolicy: + Type: AWS::IAM::Policy + Properties: + PolicyName: !Sub ${env}-${AWS::StackName}-task-execution-role-policy + Roles: [!Ref ECSTaskExecutionRole] + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "secretsmanager:GetSecretValue" + Resource: "*" + - Effect: Allow + Action: + - "ssm:GetParameters" + - "ssm:GetParameter" + - "ssm:GetParametersByPath" + Resource: + - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sdp/*" + - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sdp/${env}/*" + - Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${env}-${AWS::StackName}*" + - Effect: Allow + Action: + - "ecr:GetAuthorizationToken" + - "ecr:BatchCheckLayerAvailability" + - "ecr:GetDownloadUrlForLayer" + - "ecr:BatchGetImage" + Resource: !Sub "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/sdp-dev" + - Effect: Allow + Action: + - "ecr:GetAuthorizationToken" + Resource: "*" + - Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + Resource: + - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${env}-${AWS::StackName}/tss:*" + - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${env}-${AWS::StackName}/sdp:*" + + ECSTaskExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy + - arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess + + ECSTaskRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess + Policies: + - PolicyName: SESSendEmailPolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ses:SendEmail + - ses:SendRawEmail + Resource: '*' + + FrontendTaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: !Sub ${env}-${AWS::StackName}-frontend + Cpu: 1024 + Memory: 3072 + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn + TaskRoleArn: !GetAtt ECSTaskRole.Arn + ContainerDefinitions: + - Name: frontend + Image: !Ref FrontendImage + Essential: true + PortMappings: + - ContainerPort: 80 + Protocol: tcp + Environment: + - Name: API_URL + Value: !Sub https://sdp-backend.${DomainName} + - Name: STELLAR_EXPERT_URL + Value: https://stellar.expert/explorer/testnet + - Name: HORIZON_URL + Value: https://horizon-testnet.stellar.org + - Name: USDC_ASSET_ISSUER + Value: GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5 + - Name: RECAPTCHA_SITE_KEY + Value: 6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb + - Name: SINGLE_TENANT_MODE + Value: "false" + - Name: PUBLIC_ALB_DNS + Value: + Fn::ImportValue: sdp-network-public-alb-dns + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-create-group: 'true' + awslogs-group: !Sub /ecs/${env}-${AWS::StackName} + awslogs-region: !Ref AWS::Region + awslogs-stream-prefix: frontend + EntryPoint: + - /bin/sh + - -c + Command: + - | + cat /usr/share/nginx/html/index.html && \ + mkdir -p /usr/share/nginx/html/settings && \ + echo "window._env_ = { + API_URL: \"$API_URL\", + RECAPTCHA_SITE_KEY: \"$RECAPTCHA_SITE_KEY\", + HORIZON_URL: \"$HORIZON_URL\", + STELLAR_EXPERT_URL: \"$STELLAR_EXPERT_URL\", + SINGLE_TENANT_MODE: $SINGLE_TENANT_MODE + };" > /usr/share/nginx/html/settings/env-config.js && + exec nginx -g 'daemon off;' + + TSSTaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: !Sub ${env}-${AWS::StackName}-tss + Cpu: 1024 + Memory: 3072 + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn + TaskRoleArn: !GetAtt ECSTaskRole.Arn + ContainerDefinitions: + - Name: tss + Image: !Ref BackendImage + Essential: true + PortMappings: + - ContainerPort: 9000 + Protocol: tcp + - ContainerPort: 9002 + Protocol: tcp + EntryPoint: + - /bin/bash + - -c + Command: + - | + set -e + echo "Starting TSS initialization..." + + # Wait for database to be ready + sleep 10 + + echo "Verifying and managing channel accounts..." + # First verify and cleanup invalid accounts + ./stellar-disbursement-platform channel-accounts verify --delete-invalid-accounts + + # Ensure we have the required number of channel accounts + ./stellar-disbursement-platform channel-accounts ensure 3 + + echo "Starting TSS server..." + # Start the TSS server + exec ./stellar-disbursement-platform tss + Environment: + - Name: LOG_LEVEL + Value: info + - Name: NETWORK_PASSPHRASE + Value: "Test SDF Network ; September 2015" + - Name: HORIZON_URL + Value: "https://horizon-testnet.stellar.org" + - Name: NUM_CHANNEL_ACCOUNTS + Value: "3" + - Name: MAX_BASE_FEE + Value: "100" + - Name: TSS_METRICS_PORT + Value: "9002" + - Name: TSS_METRICS_TYPE + Value: "TSS_PROMETHEUS" + - Name: EVENT_BROKER_TYPE + Value: "NONE" + - Name: BROKER_URLS + Value: "kafka:9092" + - Name: CONSUMER_GROUP_ID + Value: "group-id" + - Name: KAFKA_SECURITY_PROTOCOL + Value: "PLAINTEXT" + HealthCheck: + Command: + - CMD-SHELL + - curl -f http://localhost:9002/metrics || exit 1 + Interval: 30 + Timeout: 5 + Retries: 3 + StartPeriod: 60 + Secrets: + - Name: DISTRIBUTION_PUBLIC_KEY + ValueFrom: !Sub + - "${secret}:public_key::" + - secret: !ImportValue sdp-keys-distribution-secret-arn + - Name: DISTRIBUTION_SEED + ValueFrom: !Sub + - "${secret}:seed::" + - secret: !ImportValue sdp-keys-distribution-secret-arn + - Name: DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE + ValueFrom: !Sub + - "${secret}:encryption_passphrase::" + - secret: !ImportValue sdp-keys-distribution-secret-arn + - Name: CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE + ValueFrom: !Sub + - "${secret}:encryption_passphrase::" + - secret: !ImportValue sdp-keys-channel-secret-arn + - Name: DATABASE_URL + ValueFrom: !Sub + - "${secret}:DATABASE_URL::" + - secret: !ImportValue sdp-database-database-url-secret + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-create-group: 'true' + awslogs-group: !Sub /ecs/${env}-${AWS::StackName}/tss + awslogs-region: !Ref AWS::Region + awslogs-stream-prefix: tss + awslogs-multiline-pattern: '^\d{4}-\d{2}-\d{2}' + awslogs-datetime-format: '%Y-%m-%d %H:%M:%S' + LinuxParameters: + InitProcessEnabled: true + + SDPTaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: !Sub ${env}-${AWS::StackName}-sdp + Cpu: 1024 + Memory: 3072 + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn + TaskRoleArn: !GetAtt ECSTaskRole.Arn + ContainerDefinitions: + - Name: sdp + Image: !Ref BackendImage + Essential: true + PortMappings: + - ContainerPort: 8000 + Protocol: tcp + - ContainerPort: 8002 + Protocol: tcp + - ContainerPort: 8003 + Protocol: tcp + - ContainerPort: 2345 + Protocol: tcp + EntryPoint: + - /bin/bash + - -c + Command: + - | + ./stellar-disbursement-platform db admin migrate up && \ + ./stellar-disbursement-platform db tss migrate up && \ + ./stellar-disbursement-platform db auth migrate up --all && \ + ./stellar-disbursement-platform db sdp migrate up --all && \ + /go/bin/dlv exec --continue --accept-multiclient --headless --listen=:2345 --api-version=2 --log ./stellar-disbursement-platform -- serve + LinuxParameters: + Capabilities: + Add: + - SYS_PTRACE + Environment: + - Name: AWS_REGION + Value: !Ref AWS::Region + - Name: BASE_URL + Value: !Sub https://sdp-backend.${DomainName} + - Name: SDP_UI_BASE_URL + Value: !Sub https://sdp-frontend.${DomainName} + - Name: DISABLE_RECAPTCHA + Value: 'true' + - Name: ENVIRONMENT + Value: !Ref env + - Name: SMS_SENDER_TYPE + Value: !Ref SmsSenderType + - Name: ENABLE_MFA + Value: 'false' + - Name: NETWORK_PASSPHRASE + Value: Test SDF Network ; September 2015 + - Name: LOG_LEVEL + Value: debug + - Name: HORIZON_URL + Value: https://horizon-testnet.stellar.org + - Name: INSTANCE_NAME + Value: "Stellar Disbursement Platform" + - Name: CORS_ALLOWED_ORIGINS + Value: "*" + - Name: SEP24_JWT_SECRET + Value: "jwt_secret_1234567890" + - Name: ANCHOR_PLATFORM_BASE_PLATFORM_URL + Value: !Sub https://anchor-platform.${DomainName} + - Name: ANCHOR_PLATFORM_BASE_SEP_URL + Value: !Sub https://anchor.${DomainName} + - Name: ANCHOR_PLATFORM_OUTGOING_JWT_SECRET + Value: "mySdpToAnchorPlatformSecret" + - Name: RECAPTCHA_SITE_KEY + Value: "6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb" + - Name: ADMIN_ACCOUNT + Value: admin + - Name: ADMIN_API_KEY + Value: api_key_1234567890 + - Name: AWS_REGION + Value: !Ref AWS::Region + - Name: EVENT_BROKER_TYPE + Value: "NONE" + - Name: BROKER_URLS + Value: "kafka:9092" + - Name: CONSUMER_GROUP_ID + Value: "group-id" + - Name: KAFKA_SECURITY_PROTOCOL + Value: "PLAINTEXT" + - Name: ENABLE_SCHEDULER + Value: "true" + - Name: SCHEDULER_RECEIVER_INVITATION_JOB_SECONDS + Value: "10" + - Name: SCHEDULER_PAYMENT_JOB_SECONDS + Value: "10" + - Name: METRICS_PORT + Value: "8002" + - Name: METRICS_TYPE + Value: "PROMETHEUS" + - Name: EMAIL_SENDER_TYPE + Value: !Ref EmailSenderType + - Name: AWS_SES_SENDER_ID + Value: !Sub "noreply@${DomainName}" + Secrets: + - Name: EC256_PRIVATE_KEY + ValueFrom: !Sub + - "${secret}:private_key::" + - secret: !ImportValue sdp-keys-ec256-secret-arn + - Name: EC256_PUBLIC_KEY + ValueFrom: !Sub + - "${secret}:public_key::" + - secret: !ImportValue sdp-keys-ec256-secret-arn + - Name: SEP10_SIGNING_PRIVATE_KEY + ValueFrom: !Sub + - "${secret}:signing_private_key::" + - secret: !ImportValue sdp-keys-sep10-secret-arn + - Name: SEP10_SIGNING_PUBLIC_KEY + ValueFrom: !Sub + - "${secret}:signing_public_key::" + - secret: !ImportValue sdp-keys-sep10-secret-arn + - Name: DISTRIBUTION_SEED + ValueFrom: !Sub + - "${secret}:seed::" + - secret: !ImportValue sdp-keys-distribution-secret-arn + - Name: DISTRIBUTION_PUBLIC_KEY + ValueFrom: !Sub + - "${secret}:public_key::" + - secret: !ImportValue sdp-keys-distribution-secret-arn + - Name: DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE + ValueFrom: !Sub + - "${secret}:encryption_passphrase::" + - secret: !ImportValue sdp-keys-distribution-secret-arn + - Name: CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE + ValueFrom: !Sub + - "${secret}:encryption_passphrase::" + - secret: !ImportValue sdp-keys-channel-secret-arn + - Name: DATABASE_URL + ValueFrom: !Sub + - "${secret}:DATABASE_URL::" + - secret: !ImportValue sdp-database-database-url-secret + - Name: RECAPTCHA_SITE_SECRET_KEY + ValueFrom: !Ref RecaptchaSiteSecretKeyParam + - Name: AWS_ACCESS_KEY_ID + ValueFrom: !Ref AWSSESAccessKeyParam + - Name: AWS_SECRET_ACCESS_KEY + ValueFrom: !Ref AWSSESSecretKeyParam + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-create-group: 'true' + awslogs-group: !Sub /ecs/${env}-${AWS::StackName}/backend + awslogs-region: !Ref AWS::Region + awslogs-stream-prefix: sdp + awslogs-multiline-pattern: '^\d{4}-\d{2}-\d{2}' + awslogs-datetime-format: '%Y-%m-%d %H:%M:%S' + + AnchorTaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: !Sub ${env}-${AWS::StackName}-anchor + Cpu: 1024 + Memory: 3072 + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn + TaskRoleArn: !GetAtt ECSTaskRole.Arn + ContainerDefinitions: + - Name: anchorplatform + Image: !Ref AnchorImage + Essential: true + PortMappings: + - ContainerPort: 8080 + Protocol: tcp + Name: sep-server + AppProtocol: http + - ContainerPort: 8085 + Protocol: tcp + Name: platform-server + AppProtocol: http + - ContainerPort: 8082 + Protocol: tcp + Name: metrics + AppProtocol: http + Command: + - "--sep-server" + - "--platform-server" + - "--platform" + - "linux/amd64" + Environment: + - Name: HOST_URL + Value: !Sub https://anchor.${DomainName} + - Name: SEP_SERVER_PORT + Value: "8080" + - Name: CALLBACK_API_BASE_URL + Value: !Sub https://sdp-backend.${DomainName} + - Name: CALLBACK_API_AUTH_TYPE + Value: "none" + - Name: PLATFORM_SERVER_AUTH_TYPE + Value: "JWT" + - Name: APP_LOGGING_LEVEL + Value: "INFO" + - Name: DATA_TYPE + Value: "postgres" + - Name: DATA_DATABASE + Value: "postgres" + - Name: DATA_FLYWAY_ENABLED + Value: "true" + - Name: DATA_DDL_AUTO + Value: "update" + - Name: METRICS_ENABLED + Value: "false" + - Name: METRICS_EXTRAS_ENABLED + Value: "false" + - Name: EVENT_BROKER_TYPE + Value: "NONE" + - Name: SEP10_ENABLED + Value: "true" + - Name: SEP10_WEB_AUTH_DOMAIN + Value: !Sub anchor.${DomainName} + - Name: SEP10_HOME_DOMAINS + Value: !Sub "*.${DomainName}" + - Name: SEP24_ENABLED + Value: "true" + - Name: SEP24_INTERACTIVE_URL_BASE_URL + Value: !Sub https://sdp-backend.${DomainName}/wallet-registration/start + - Name: SEP24_INTERACTIVE_URL_JWT_EXPIRATION + Value: "1800" + - Name: SEP24_MORE_INFO_URL_BASE_URL + Value: !Sub https://sdp-backend.${DomainName}/wallet-registration/start + - Name: SEP1_ENABLED + Value: "true" + - Name: SEP1_TOML_TYPE + Value: "url" + - Name: SEP1_TOML_VALUE + Value: !Sub https://sdp-backend.${DomainName}/.well-known/stellar.toml + - Name: SECRET_PLATFORM_API_AUTH_SECRET + Value: "mySdpToAnchorPlatformSecret" + - Name: SECRET_SEP10_JWT_SECRET + Value: "jwt_secret_1234567890" + - Name: SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET + Value: "jwt_secret_1234567890" + - Name: SECRET_SEP24_MORE_INFO_URL_JWT_SECRET + Value: "jwt_secret_1234567890" + - Name: ASSETS_TYPE + Value: "json" + - Name: ASSETS_VALUE + Value: !Sub + - | + { + "assets": [ + { + "sep24_enabled": true, + "schema": "stellar", + "code": "USDC", + "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + "distribution_account": "${distributionAccount}", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + }, + { + "sep24_enabled": true, + "schema": "stellar", + "code": "native", + "issuer": "", + "distribution_account": "${distributionAccount}", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + } + ] + } + - distributionAccount: !Sub + - "{{resolve:secretsmanager:${SecretArn}:SecretString:public_key}}" + - SecretArn: !ImportValue sdp-keys-distribution-secret-arn + Secrets: + - Name: SECRET_DATA_USERNAME + ValueFrom: !Sub + - "${secret}:username::" + - secret: !ImportValue sdp-database-db-secret + - Name: SECRET_DATA_PASSWORD + ValueFrom: !Sub + - "${secret}:password::" + - secret: !ImportValue sdp-database-db-secret + - Name: DATA_SERVER + ValueFrom: !Sub + - "${secret}:host::" + - secret: !ImportValue sdp-database-db-secret + - Name: SECRET_SEP10_SIGNING_SEED + ValueFrom: !Sub + - "${secret}:signing_private_key::" + - secret: !ImportValue sdp-keys-sep10-secret-arn + - Name: DISTRIBUTION_PUBLIC_KEY + ValueFrom: !Sub + - "${secret}:public_key::" + - secret: !ImportValue sdp-keys-distribution-secret-arn + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-create-group: 'true' + awslogs-group: !Sub /ecs/${env}-${AWS::StackName} + awslogs-region: !Ref AWS::Region + awslogs-stream-prefix: anchor + + TSSLogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Sub /ecs/${env}-${AWS::StackName}/tss + RetentionInDays: 1 + + SDPLogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Sub /ecs/${env}-${AWS::StackName}/sdp + RetentionInDays: 1 + + FrontendService: + Type: AWS::ECS::Service + DependsOn: + - FrontendListenerRule + - SDPService + Properties: + ServiceName: !Sub ${env}-${AWS::StackName}-frontend + Cluster: !Ref ECSCluster + TaskDefinition: !Ref FrontendTaskDefinition + DesiredCount: 1 + LaunchType: FARGATE + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: DISABLED + SecurityGroups: + - Fn::ImportValue: sdp-network-ecs-services-sg + Subnets: + - Fn::ImportValue: sdp-network-private-subnet-1 + - Fn::ImportValue: sdp-network-private-subnet-2 + LoadBalancers: + - ContainerName: frontend + ContainerPort: 80 + TargetGroupArn: !Ref FrontendTargetGroup + HealthCheckGracePeriodSeconds: 300 + + TSSService: + Type: AWS::ECS::Service + DependsOn: + - SDPService + Properties: + DeploymentConfiguration: + DeploymentCircuitBreaker: + Enable: false + Rollback: false + MaximumPercent: 100 + MinimumHealthyPercent: 0 + ServiceName: !Sub ${env}-${AWS::StackName}-tss + Cluster: !Ref ECSCluster + TaskDefinition: !Ref TSSTaskDefinition + DesiredCount: 1 + LaunchType: FARGATE + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: DISABLED + SecurityGroups: + - Fn::ImportValue: sdp-network-ecs-services-sg # Updated to use the single ECS services security group + Subnets: + - Fn::ImportValue: sdp-network-private-subnet-1 + - Fn::ImportValue: sdp-network-private-subnet-2 + + SDPService: + Type: AWS::ECS::Service + DependsOn: + - SDPListenerRule + - SDPListenerRule + - TenantListenerRule + - SDPTargetGroup + - TenantTargetGroup + - SDPTaskDefinition + - SDPLogGroup + Properties: + ServiceName: !Sub ${env}-${AWS::StackName}-sdp + Cluster: !Ref ECSCluster + TaskDefinition: !Ref SDPTaskDefinition + DesiredCount: 1 + LaunchType: FARGATE + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: DISABLED + SecurityGroups: + - Fn::ImportValue: sdp-network-ecs-services-sg + Subnets: + - Fn::ImportValue: sdp-network-private-subnet-1 + - Fn::ImportValue: sdp-network-private-subnet-2 + LoadBalancers: + - ContainerName: sdp + ContainerPort: 8000 + TargetGroupArn: !Ref SDPTargetGroup + - ContainerName: sdp + ContainerPort: 8003 + TargetGroupArn: !Ref TenantTargetGroup + HealthCheckGracePeriodSeconds: 300 + DeploymentConfiguration: + DeploymentCircuitBreaker: + Enable: true + Rollback: true + + AnchorService: + Type: AWS::ECS::Service + DependsOn: + - AnchorSepListenerRule + - SDPService + Properties: + ServiceName: !Sub ${env}-${AWS::StackName}-anchor + Cluster: !Ref ECSCluster + TaskDefinition: !Ref AnchorTaskDefinition + DesiredCount: 1 + LaunchType: FARGATE + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: DISABLED + SecurityGroups: + - Fn::ImportValue: sdp-network-ecs-services-sg + Subnets: + - Fn::ImportValue: sdp-network-private-subnet-1 + - Fn::ImportValue: sdp-network-private-subnet-2 + LoadBalancers: + - ContainerName: anchorplatform + ContainerPort: 8080 + TargetGroupArn: !Ref AnchorSepTargetGroup + - ContainerName: anchorplatform + ContainerPort: 8085 + TargetGroupArn: !Ref AnchorPlatformTargetGroup + HealthCheckGracePeriodSeconds: 300 + + BaseDomainRecord: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneName: !Sub ${DomainName}. + Name: !Ref DomainName + Type: A + AliasTarget: + DNSName: + Fn::ImportValue: sdp-network-public-alb-dns + HostedZoneId: + Fn::ImportValue: sdp-network-public-alb-hosted-zone + EvaluateTargetHealth: true + + FrontendDNSRecord: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneName: !Sub ${DomainName}. + Name: !Sub sdp-frontend.${DomainName}. + Type: A + AliasTarget: + DNSName: + Fn::ImportValue: sdp-network-public-alb-dns + HostedZoneId: + Fn::ImportValue: sdp-network-public-alb-hosted-zone + EvaluateTargetHealth: true + + BackendDNSRecord: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneName: !Sub ${DomainName}. + Name: !Sub sdp-backend.${DomainName}. + Type: A + AliasTarget: + DNSName: + Fn::ImportValue: sdp-network-public-alb-dns + HostedZoneId: + Fn::ImportValue: sdp-network-public-alb-hosted-zone + EvaluateTargetHealth: true + + AnchorDNSRecord: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneName: !Sub ${DomainName}. + Name: !Sub anchor.${DomainName}. + Type: A + AliasTarget: + DNSName: + Fn::ImportValue: sdp-network-public-alb-dns + HostedZoneId: + Fn::ImportValue: sdp-network-public-alb-hosted-zone + EvaluateTargetHealth: true + + AnchorPlatformPrivateDNSRecord: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneName: !Sub ${DomainName}. + Name: !Sub anchor-platform.${DomainName}. + Type: A + AliasTarget: + DNSName: + Fn::ImportValue: sdp-network-private-alb-dns + HostedZoneId: + Fn::ImportValue: sdp-network-private-alb-hosted-zone + EvaluateTargetHealth: true + + AdminDNSRecord: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneName: !Sub ${DomainName}. + Name: !Sub admin.${DomainName}. + Type: A + AliasTarget: + DNSName: + Fn::ImportValue: sdp-network-private-alb-dns + HostedZoneId: + Fn::ImportValue: sdp-network-private-alb-hosted-zone + EvaluateTargetHealth: true + + WildcardDNSRecord: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneName: !Sub ${DomainName}. + Name: !Sub "*.${DomainName}." + Type: A + AliasTarget: + DNSName: + Fn::ImportValue: sdp-network-public-alb-dns + HostedZoneId: + Fn::ImportValue: sdp-network-public-alb-hosted-zone + EvaluateTargetHealth: true + + RecaptchaSiteSecretKeyParam: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub "/sdp/${env}/RECAPTCHA_SITE_SECRET_KEY" + Type: String + Value: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" + Tags: + env: !Ref env + + AWSSESAccessKeyParam: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub "/sdp/${env}/AWS_ACCESS_KEY_ID" + Type: String + Value: !Ref SESUserAccessKey + Tags: + env: !Ref env + + AWSSESSecretKeyParam: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub "/sdp/${env}/AWS_SECRET_ACCESS_KEY" + Type: String + Value: !GetAtt SESUserAccessKey.SecretAccessKey + Tags: + env: !Ref env + + AWSSESSenderIDParam: + Type: AWS::SSM::Parameter + Properties: + Name: !Sub "/sdp/${env}/AWS_SES_SENDER_ID" + Type: String + Value: !Sub "noreply@${DomainName}" + Tags: + env: !Ref env + + EmailDomainIdentity: + Type: AWS::SES::EmailIdentity + Properties: + EmailIdentity: !Ref DomainName + DkimAttributes: + SigningEnabled: true + ConfigurationSetAttributes: + ConfigurationSetName: !Ref EmailConfigurationSet + + DkimRecord1: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneId: !Ref HostedZoneId + Name: !GetAtt EmailDomainIdentity.DkimDNSTokenName1 + Type: CNAME + TTL: 300 + ResourceRecords: + - !GetAtt EmailDomainIdentity.DkimDNSTokenValue1 + + DkimRecord2: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneId: !Ref HostedZoneId + Name: !GetAtt EmailDomainIdentity.DkimDNSTokenName2 + Type: CNAME + TTL: 300 + ResourceRecords: + - !GetAtt EmailDomainIdentity.DkimDNSTokenValue2 + + DkimRecord3: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneId: !Ref HostedZoneId + Name: !GetAtt EmailDomainIdentity.DkimDNSTokenName3 + Type: CNAME + TTL: 300 + ResourceRecords: + - !GetAtt EmailDomainIdentity.DkimDNSTokenValue3 + + EmailConfigurationSet: + Type: AWS::SES::ConfigurationSet + Properties: + Name: !Sub "${env}-${AWS::StackName}-config-set" + DeliveryOptions: + TlsPolicy: REQUIRE + ReputationOptions: + ReputationMetricsEnabled: true + SendingOptions: + SendingEnabled: true + SuppressionOptions: + SuppressedReasons: + - BOUNCE + - COMPLAINT + + SESUser: + Type: AWS::IAM::User + Properties: + UserName: !Sub "${env}-${AWS::StackName}-ses-smtp" + Policies: + - PolicyName: SESSendEmail + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ses:SendRawEmail + - ses:SendEmail + Resource: "*" + + SESUserAccessKey: + Type: AWS::IAM::AccessKey + Properties: + UserName: !Ref SESUser + + Outputs: + FrontendURL: + Value: !Sub https://sdp-frontend.${DomainName} + Export: + Name: !Sub ${AWS::StackName}-sdp-frontend-url + + DomainName: + Value: !Ref DomainName + Export: + Name: !Sub ${AWS::StackName}-domain-name diff --git a/resources/aws/cloudformation/sdp-eks.yaml b/resources/aws/cloudformation/sdp-eks.yaml new file mode 100644 index 000000000..004bd8535 --- /dev/null +++ b/resources/aws/cloudformation/sdp-eks.yaml @@ -0,0 +1,538 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'EKS Cluster for SDP' + +Parameters: + env: + Type: String + Default: "dev" + AllowedValues: + - dev + - staging + - prod + + NetworkStackName: + Type: String + Default: sdp-network + Description: Name of the networking stack + + DatabaseStackName: + Type: String + Default: sdp-database + Description: Name of the database stack + + KeysStackName: + Type: String + Default: sdp-keys + Description: Name of the keys/secrets stack + +Resources: + ######################################################################## + # EKS Cluster + ######################################################################## + EKSCluster: + Type: AWS::EKS::Cluster + Properties: + Name: !Sub "${env}-sdp-cluster" + Version: "1.27" + RoleArn: !GetAtt EKSClusterRole.Arn + ResourcesVpcConfig: + SecurityGroupIds: + - !Ref EKSClusterSecurityGroup + SubnetIds: + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-1 + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-2 + Logging: + ClusterLogging: + EnabledTypes: [] + + ######################################################################## + # OIDC Provider for IRSA + ######################################################################## + OIDCProvider: + Type: AWS::IAM::OIDCProvider + DependsOn: [EKSCluster, ClusterOIDCId] + Properties: + Url: !Sub "https://oidc.eks.${AWS::Region}.amazonaws.com/id/${ClusterOIDCId.OIDCId}" + ClientIdList: + - "sts.amazonaws.com" + ThumbprintList: + - "9e99a48a9960b14926bb7f3b02e22da2b0ab7280" + + ######################################################################## + # NodeGroup + ######################################################################## + + EKSNodeGroup: # Changed from EKSNodeGroup + Type: AWS::EKS::Nodegroup + Properties: + ClusterName: !Ref EKSCluster + NodeRole: !GetAtt EKSNodeGroupRole.Arn + ScalingConfig: + MinSize: 2 + DesiredSize: 3 + MaxSize: 4 + InstanceTypes: + - t3.small + Subnets: + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-1 + - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-2 + + ######################################################################## + # IAM Roles + ######################################################################## + EKSClusterRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: eks.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AmazonEKSClusterPolicy + + CertManagerRole: + Type: AWS::IAM::Role + DependsOn: [OIDCProvider, ClusterOIDCId] + Properties: + RoleName: !Sub "${env}-cert-manager-role" + AssumeRolePolicyDocument: + Fn::Sub: + - | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:sub": "system:serviceaccount:cert-manager:cert-manager", + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:aud": "sts.amazonaws.com" + } + } + } + ] + } + - OIDCId: !GetAtt ClusterOIDCId.OIDCId + Policies: + - PolicyName: Route53Access + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - 'route53:GetChange' + Resource: 'arn:aws:route53:::change/*' + - Effect: Allow + Action: + - 'route53:ChangeResourceRecordSets' + - 'route53:ListResourceRecordSets' + Resource: 'arn:aws:route53:::hostedzone/*' + - Effect: Allow + Action: 'route53:ListHostedZonesByName' + Resource: '*' + + EKSNodeGroupRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ec2.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy + - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy + - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly + Policies: + - PolicyName: SecretsAccess + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - secretsmanager:GetSecretValue + Resource: + - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn + - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret + + ExternalDNSPolicy: + Type: AWS::IAM::ManagedPolicy + Properties: + Description: Policy for external-dns to manage Route53 records + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - route53:ChangeResourceRecordSets + Resource: + - !Sub "arn:aws:route53:::hostedzone/*" + - Effect: Allow + Action: + - route53:ListHostedZones + - route53:ListResourceRecordSets + - route53:ListTagsForResource + Resource: ["*"] + + ExternalDNSRole: + Type: AWS::IAM::Role + DependsOn: [OIDCProvider, ClusterOIDCId] + Properties: + RoleName: !Sub "${env}-external-dns-role" + ManagedPolicyArns: + - !Ref ExternalDNSPolicy + AssumeRolePolicyDocument: + Fn::Sub: + - | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:sub": "system:serviceaccount:external-dns:external-dns", + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:aud": "sts.amazonaws.com" + } + } + } + ] + } + - OIDCId: !GetAtt ClusterOIDCId.OIDCId + + ######################################################################## + # Security Group for EKS + ######################################################################## + EKSClusterSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for EKS cluster + VpcId: + Fn::ImportValue: !Sub ${NetworkStackName}-vpc-id + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 + CidrIp: + Fn::ImportValue: !Sub ${NetworkStackName}-vpc-cidr + + RDSIngressRule: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: + Fn::ImportValue: !Sub ${DatabaseStackName}-db-sg # This imports the RDS security group ID + IpProtocol: tcp + FromPort: 5432 + ToPort: 5432 + SourceSecurityGroupId: !Ref EKSClusterSecurityGroup # This references the EKS cluster security group + + NodeToRDSIngressRule: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: + Fn::ImportValue: !Sub ${DatabaseStackName}-db-sg + IpProtocol: tcp + FromPort: 5432 + ToPort: 5432 + SourceSecurityGroupId: !Ref EKSNodeSecurityGroup + + EKSNodeSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for EKS worker nodes + VpcId: + Fn::ImportValue: !Sub ${NetworkStackName}-vpc-id + Tags: + - Key: Name + Value: !Sub "${env}-sdp-cluster-node-sg" + + EKSCreatedSGToRDSIngressRule: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: + Fn::ImportValue: !Sub ${DatabaseStackName}-db-sg + IpProtocol: tcp + FromPort: 5432 + ToPort: 5432 + SourceSecurityGroupId: !GetAtt EKSCluster.ClusterSecurityGroupId + + NodeGroupSecurityGroupIngress: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: !Ref EKSNodeSecurityGroup + SourceSecurityGroupId: !Ref EKSNodeSecurityGroup + IpProtocol: '-1' + FromPort: -1 + ToPort: -1 + + NodeToClusterIngress: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: !Ref EKSClusterSecurityGroup + SourceSecurityGroupId: !Ref EKSNodeSecurityGroup + IpProtocol: '-1' + FromPort: -1 + ToPort: -1 + + ClusterToNodeIngress: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: !Ref EKSNodeSecurityGroup + SourceSecurityGroupId: !Ref EKSClusterSecurityGroup + IpProtocol: '-1' + FromPort: -1 + ToPort: -1 + ######################################################################## + # Service Account Role for SDP + ######################################################################## + ExternalSecretsOperatorRole: + Type: AWS::IAM::Role + DependsOn: [OIDCProvider, ClusterOIDCId] + Properties: + RoleName: !Sub "${env}-${AWS::StackName}-eso-role" + AssumeRolePolicyDocument: + Fn::Sub: + - | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:aud": "sts.amazonaws.com", + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:sub": "system:serviceaccount:external-secrets:external-secrets" + } + } + } + ] + } + - OIDCId: !GetAtt ClusterOIDCId.OIDCId + Policies: + - PolicyName: ExternalSecretsAccess + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - 'secretsmanager:GetSecretValue' + - 'secretsmanager:DescribeSecret' + Resource: + - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/${env}/*" + - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/*" + - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn + - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret + - Fn::ImportValue: !Sub ${DatabaseStackName}-db-secret-arn + + SDPServiceAccountRole: + Type: AWS::IAM::Role + DependsOn: [OIDCProvider, ClusterOIDCId] + Properties: + RoleName: !Sub "${env}-sdp-service-account" + AssumeRolePolicyDocument: + Fn::Sub: + - | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:aud": "sts.amazonaws.com", + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:sub": "system:serviceaccount:external-secrets:external-secrets" + } + } + } + ] + } + - OIDCId: !GetAtt ClusterOIDCId.OIDCId + Policies: + - PolicyName: SecretsAccess + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - secretsmanager:GetSecretValue + Resource: + - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn + - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret + + ClusterOIDCIdFunction: + Type: AWS::Lambda::Function + Properties: + Handler: index.handler + Role: !GetAtt LambdaExecutionRole.Arn + Code: + ZipFile: | + import boto3 + import cfnresponse + import json + + def handler(event, context): + try: + if event['RequestType'] in ['Create', 'Update']: + eks = boto3.client('eks') + cluster_name = event['ResourceProperties']['ClusterName'] + + response = eks.describe_cluster(name=cluster_name) + issuer_url = response['cluster']['identity']['oidc']['issuer'] + oidc_id = issuer_url.split('/')[-1] + + cfnresponse.send(event, context, cfnresponse.SUCCESS, { + 'OIDCId': oidc_id + }) + else: + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) + except Exception as e: + print(e) + cfnresponse.send(event, context, cfnresponse.FAILED, {}) + Runtime: python3.9 + Timeout: 30 + + LambdaExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: EKSDescribe + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: eks:DescribeCluster + Resource: !GetAtt EKSCluster.Arn + + ClusterOIDCId: + Type: Custom::OIDCId + Properties: + ServiceToken: !GetAtt ClusterOIDCIdFunction.Arn + ClusterName: !Ref EKSCluster + + SecretStoreRole: + Type: AWS::IAM::Role + DependsOn: [OIDCProvider, ClusterOIDCId] + Properties: + RoleName: !Sub "${env}-${AWS::StackName}-secretstore-role" + AssumeRolePolicyDocument: + Fn::Sub: + - | + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:sub": "system:serviceaccount:sdp:external-secrets-sa", + "oidc.eks.${AWS::Region}.amazonaws.com/id/${OIDCId}:aud": "sts.amazonaws.com" + } + } + } + ] + } + - OIDCId: !GetAtt ClusterOIDCId.OIDCId + Policies: + - PolicyName: SecretsAccess + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - 'secretsmanager:GetSecretValue' + - 'secretsmanager:DescribeSecret' + Resource: + - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/${env}/*" + - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/*" + - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn + - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn + - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret + - Fn::ImportValue: !Sub ${DatabaseStackName}-db-secret-arn + +Outputs: + ClusterName: + Description: EKS cluster name + Value: !Ref EKSCluster + Export: + Name: !Sub "${AWS::StackName}-cluster-name" + + ClusterSecurityGroupId: + Description: Security Group ID for EKS cluster + Value: !Ref EKSClusterSecurityGroup + Export: + Name: !Sub "${AWS::StackName}-cluster-sg" + + SecretStoreRoleArn: + Description: IAM Role ARN for SecretStore + Value: !GetAtt SecretStoreRole.Arn + Export: + Name: !Sub "${AWS::StackName}-secretstore-role-arn" + + CertManagerRoleArn: + Description: IAM Role ARN for cert-manager + Value: !GetAtt CertManagerRole.Arn + Export: + Name: !Sub "${AWS::StackName}-cert-manager-role-arn" + + ExternalSecretsOperatorRoleArn: + Description: IAM Role ARN for External Secrets Operator + Value: !GetAtt ExternalSecretsOperatorRole.Arn + Export: + Name: !Sub "${AWS::StackName}-eso-role-arn" + + ServiceAccountRoleArn: + Description: IAM Role ARN for SDP Service Account + Value: !GetAtt SDPServiceAccountRole.Arn + Export: + Name: !Sub "${AWS::StackName}-service-account-role-arn" + + ExternalDNSRoleArn: + Description: IAM Role ARN for external-dns + Value: !GetAtt ExternalDNSRole.Arn + Export: + Name: !Sub "${AWS::StackName}-external-dns-role-arn" \ No newline at end of file diff --git a/resources/aws/cloudformation/sdp-keys.yaml b/resources/aws/cloudformation/sdp-keys.yaml new file mode 100644 index 000000000..84f9f3c6e --- /dev/null +++ b/resources/aws/cloudformation/sdp-keys.yaml @@ -0,0 +1,491 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Stack for managing Stellar and encryption keys in Secrets Manager' + +Parameters: + env: + Type: String + Default: "dev" + + namespace: + Type: String + Description: "Kubernetes only. namespace where SDP will be deployed" + Default: "sdp" + + DistributionAccountEncryptionPassphrase: + Type: String + Default: "" + NoEcho: true + + ChannelAccountEncryptionPassphrase: + Type: String + Default: "" + NoEcho: true + + SEP10SigningPrivateKey: + Type: String + Default: "" + NoEcho: true + + SEP10SigningPublicKey: + Type: String + Default: "" + + DistributionSeed: + Type: String + Default: "" + NoEcho: true + + DistributionPublicKey: + Type: String + Default: "" + + EC256PrivateKey: + Type: String + NoEcho: true + Default: | + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIPRRtyc5EQoNPFhkcDzC47B2Zpo5b0NiM3Ftvky86+bEoAoGCCqGSM49 + AwEHoUQDQgAEWinhVw0QHkZDeZ777zfBKT0cupULkpEd8Y52iPs76AT7JQ1cuGbm + jxJASNwp907KzNzOZJSV07bFdN/Tkwebgg== + -----END EC PRIVATE KEY----- + + EC256PublicKey: + Type: String + Default: | + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWinhVw0QHkZDeZ777zfBKT0cupUL + kpEd8Y52iPs76AT7JQ1cuGbmjxJASNwp907KzNzOZJSV07bFdN/Tkwebgg== + -----END PUBLIC KEY----- + +Conditions: + GenerateSep10Keys: !Equals [ !Ref SEP10SigningPrivateKey, "" ] + GenerateDistributionKeys: !Equals [ !Ref DistributionSeed, "" ] + GenerateChannelKeys: !Equals [ !Ref ChannelAccountEncryptionPassphrase, "" ] + +Resources: + StellarKeyGenRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: SecretsManagerAccess + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - secretsmanager:CreateSecret + - secretsmanager:PutSecretValue + - secretsmanager:UpdateSecret + Resource: + - !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/${env}/*' + + StellarKeyGenRolePolicy: + Type: AWS::IAM::Policy + Properties: + PolicyName: !Sub ${AWS::StackName}-stellar-keygen-policy + Roles: + - !Ref StellarKeyGenRole + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + Resource: + - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*" + + StellarSDKLayer: + Type: AWS::Lambda::LayerVersion + Properties: + LayerName: stellar-sdk-layer + Content: + S3Bucket: stellar-layer + S3Key: stellar-layer.zip + CompatibleRuntimes: + - nodejs18.x + + StellarKeyGenFunction: + Type: AWS::Lambda::Function + Properties: + Runtime: nodejs18.x + Handler: index.handler + Role: !GetAtt StellarKeyGenRole.Arn + Timeout: 30 + Layers: + - !Ref StellarSDKLayer + Code: + ZipFile: | + const { Keypair } = require('@stellar/stellar-sdk'); + const https = require('https'); + const url = require('url'); + + async function fundTestnetAccount(publicKey) { + return new Promise((resolve, reject) => { + https.get(`https://friendbot.stellar.org?addr=${publicKey}`, (resp) => { + let data = ''; + resp.on('data', (chunk) => data += chunk); + resp.on('end', () => { + console.log('Funding response:', data); + resolve(data); + }); + }).on('error', (err) => { + console.error('Error funding account:', err); + reject(err); + }); + }); + } + + function sendResponse(event, response) { + return new Promise((resolve, reject) => { + const parsedUrl = url.parse(event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + port: 443, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'Content-Type': '', + 'Content-Length': Buffer.byteLength(JSON.stringify(response)) + } + }; + + const request = https.request(requestOptions, (resp) => { + resolve(); + }); + + request.on('error', (error) => { + console.error('Error sending response:', error); + reject(error); + }); + + request.write(JSON.stringify(response)); + request.end(); + }); + } + + exports.handler = async (event, context) => { + try { + let response = { + Status: 'SUCCESS', + RequestId: event.RequestId, + LogicalResourceId: event.LogicalResourceId, + StackId: event.StackId, + PhysicalResourceId: context.logStreamName + }; + + if (event.RequestType === 'Delete') { + console.log('Delete request, sending success response'); + } else { + console.log('Generating new keypair'); + const pair = Keypair.random(); + response.Data = { + publicKey: pair.publicKey(), + secretKey: pair.secret() + }; + + if (event.ResourceProperties.KeyPairId === 'distribution') { + console.log('Funding distribution account on testnet'); + try { + await fundTestnetAccount(pair.publicKey()); + console.log('Successfully funded account'); + } catch (fundError) { + console.error('Error funding account:', fundError); + } + } + } + + await sendResponse(event, response); + return response; + + } catch (error) { + console.error('Error:', error); + const response = { + Status: 'FAILED', + RequestId: event.RequestId, + LogicalResourceId: event.LogicalResourceId, + StackId: event.StackId, + PhysicalResourceId: context.logStreamName, + Reason: error.toString() + }; + await sendResponse(event, response); + return response; + } + }; + + Sep10KeyGenPair: + Type: Custom::StellarKeyPair + Condition: GenerateSep10Keys + Properties: + ServiceToken: !GetAtt StellarKeyGenFunction.Arn + KeyPairId: sep10 + + DistributionKeyGenPair: + Type: Custom::StellarKeyPair + Condition: GenerateDistributionKeys + Properties: + ServiceToken: !GetAtt StellarKeyGenFunction.Arn + KeyPairId: distribution + + ChannelKeyGenPair: + Type: Custom::StellarKeyPair + Condition: GenerateChannelKeys + Properties: + ServiceToken: !GetAtt StellarKeyGenFunction.Arn + KeyPairId: channel + + Sep10Secret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/sep10 + Description: "SEP10 signing keys" + SecretString: !Join + - '' + - - '{"signing_public_key":"' + - !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.publicKey, !Ref SEP10SigningPublicKey] + - '","signing_private_key":"' + - !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.secretKey, !Ref SEP10SigningPrivateKey] + - '"}' + + DistributionSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/distribution + Description: "Distribution account keys and passphrase" + SecretString: !Join + - '' + - - '{"seed":"' + - !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.secretKey, !Ref DistributionSeed] + - '","public_key":"' + - !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.publicKey, !Ref DistributionPublicKey] + - '","encryption_passphrase":"' + - !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.secretKey, !Ref DistributionAccountEncryptionPassphrase] + - '"}' + + ChannelSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/channel + Description: "Channel account encryption passphrase" + SecretString: !Join + - '' + - - '{"encryption_passphrase":"' + - !If [GenerateChannelKeys, !GetAtt ChannelKeyGenPair.secretKey, !Ref ChannelAccountEncryptionPassphrase] + - '"}' + + Ec256Secret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/ec256 + Description: "EC256 key pair" + SecretString: !Join + - '' + - - '{"private_key":"' + - !Ref EC256PrivateKey + - '","public_key":"' + - !Ref EC256PublicKey + - '"}' + # below this line is secrets for EKS. TODO: consolidate + + Ec256PrivateKeySecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/EC256_PRIVATE_KEY + Description: "EC256 private key" + SecretString: !Ref EC256PrivateKey + + Ec256PublicKeySecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/EC256_PUBLIC_KEY + Description: "EC256 public key" + SecretString: !Ref EC256PublicKey + + Sep10SigningPrivateKeySecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SEP10_SIGNING_PRIVATE_KEY + Description: "SEP10 signing private key" + SecretString: !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.secretKey, !Ref SEP10SigningPrivateKey] + + SecretSep10SigningSeed: + Type: AWS::SecretsManager::Secret + DependsOn: Sep10SigningPrivateKeySecret + Properties: + Name: !Sub /${namespace}/SECRET_SEP10_SIGNING_SEED + Description: "SEP10 signing private key" + SecretString: !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.secretKey, !Ref SEP10SigningPrivateKey] + + Sep10SigningPublicKeySecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SEP10_SIGNING_PUBLIC_KEY + Description: "SEP10 signing public key" + SecretString: !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.publicKey, !Ref SEP10SigningPublicKey] + + DistributionSeedSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/DISTRIBUTION_SEED + Description: "Distribution account seed" + SecretString: !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.secretKey, !Ref DistributionSeed] + + DistributionPublicKeySecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/DISTRIBUTION_PUBLIC_KEY + Description: "Distribution account public key" + SecretString: !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.publicKey, !Ref DistributionPublicKey] + + DistributionEncryptionPassphraseSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE + Description: "Distribution account encryption passphrase" + SecretString: !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.secretKey, !Ref DistributionAccountEncryptionPassphrase] + + ChannelEncryptionPassphraseSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE + Description: "Channel account encryption passphrase" + SecretString: !If [GenerateChannelKeys, !GetAtt ChannelKeyGenPair.secretKey, !Ref ChannelAccountEncryptionPassphrase] + + SecretPlatformApiAuthSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_PLATFORM_API_AUTH_SECRET + SecretString: "mySdpToAnchorPlatformSecret" + + SecretSep10JwtSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_SEP10_JWT_SECRET + SecretString: "jwt_secret_1234567890" + + SecretSep24InteractiveUrlJwtSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET + SecretString: "jwt_secret_1234567890" + + SecretSep24MoreInfoUrlJwtSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET + Description: "Distribution account encryption passphrase" + SecretString: "jwt_secret_1234567890" + + Sep24JwtSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/SEP24_JWT_SECRET + SecretString: "jwt_secret_1234567890" + + AnchorPlatformOutgoingJwtSecret: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/ANCHOR_PLATFORM_OUTGOING_JWT_SECRET + SecretString: "jwt_secret_1234567890" + + RecaptchaSiteKey: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /${namespace}/RECAPTCHA_SITE_KEY + SecretString: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" + + RecaptchaSiteSecretKey: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/recaptcha-site-secret-key + Description: "Recaptcha site secret key" + SecretString: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" + + RecaptchaSiteSecretKeyEKS: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/RECAPTCHA_SITE_SECRET_KEY + SecretString: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" + + AdminApiKey: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/ADMIN_API_KEY + SecretString: "admin-api-key" + +Outputs: + Sep10SecretArn: + Value: !Ref Sep10Secret + Export: + Name: !Sub ${AWS::StackName}-sep10-secret-arn + + DistributionSecretArn: + Value: !Ref DistributionSecret + Export: + Name: !Sub ${AWS::StackName}-distribution-secret-arn + + ChannelSecretArn: + Value: !Ref ChannelSecret + Export: + Name: !Sub ${AWS::StackName}-channel-secret-arn + + Ec256SecretArn: + Value: !Ref Ec256Secret + Export: + Name: !Sub ${AWS::StackName}-ec256-secret-arn + + Sep10SigningPrivateKeySecretArn: + Value: !Ref Sep10SigningPrivateKeySecret + Export: + Name: !Sub ${AWS::StackName}-sep10-signing-private-key-secret-arn + + Sep10SigningPublicKeySecretArn: + Value: !Ref Sep10SigningPublicKeySecret + Export: + Name: !Sub ${AWS::StackName}-sep10-signing-public-key-secret-arn + + DistributionSeedSecretArn: + Value: !Ref DistributionSeedSecret + Export: + Name: !Sub ${AWS::StackName}-distribution-seed-secret-arn + + DistributionPublicKeySecretArn: + Value: !Ref DistributionPublicKeySecret + Export: + Name: !Sub ${AWS::StackName}-distribution-public-key-secret-arn + + DistributionEncryptionPassphraseSecretArn: + Value: !Ref DistributionEncryptionPassphraseSecret + Export: + Name: !Sub ${AWS::StackName}-distribution-encryption-passphrase-secret-arn + + ChannelEncryptionPassphraseSecretArn: + Value: !Ref ChannelEncryptionPassphraseSecret + Export: + Name: !Sub ${AWS::StackName}-channel-encryption-passphrase-secret-arn + + Ec256PrivateKeySecretArn: + Value: !Ref Ec256PrivateKeySecret + Export: + Name: !Sub ${AWS::StackName}-ec256-private-key-secret-arn + + Ec256PublicKeySecretArn: + Value: !Ref Ec256PublicKeySecret + Export: + Name: !Sub ${AWS::StackName}-ec256-public-key-secret-arn + + RecaptchaSiteSecretKeyArn: + Value: !Ref RecaptchaSiteSecretKey + Export: + Name: !Sub ${AWS::StackName}-recaptcha-site-secret-key-arn + diff --git a/resources/aws/cloudformation/sdp-network-ecs.yaml b/resources/aws/cloudformation/sdp-network-ecs.yaml new file mode 100644 index 000000000..425d92350 --- /dev/null +++ b/resources/aws/cloudformation/sdp-network-ecs.yaml @@ -0,0 +1,411 @@ +Parameters: + AWSRegion: + Type: String + Default: "us-west-1" + + env: + Type: String + Default: "dev" + AllowedValues: + - dev + - staging + - prod + + VPCCidr: + Type: String + Default: "10.0.0.0/16" + + PublicSubnet1CIDR: + Type: String + Default: "10.0.0.0/24" + + PublicSubnet2CIDR: + Type: String + Default: "10.0.1.0/24" + + PrivateSubnet1CIDR: + Type: String + Default: "10.0.2.0/24" + + PrivateSubnet2CIDR: + Type: String + Default: "10.0.3.0/24" + + CertificateArn: + Type: String + default: "" + +Resources: + SDPVPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !Ref VPCCidr + EnableDnsHostnames: true + EnableDnsSupport: true + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-vpc + - Key: env + Value: !Ref env + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-igw + - Key: env + Value: !Ref env + + AttachGateway: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + VpcId: !Ref SDPVPC + InternetGatewayId: !Ref InternetGateway + + NatGatewayEIP: + Type: AWS::EC2::EIP + DependsOn: AttachGateway + Properties: + Domain: vpc + Tags: + - Key: env + Value: !Ref env + + # Public Subnets - Only for ALB + PublicSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PublicSubnet1CIDR + AvailabilityZone: !Select [0, !GetAZs ''] + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-public-1 + - Key: env + Value: !Ref env + - Key: Tier + Value: Public + + PublicSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PublicSubnet2CIDR + AvailabilityZone: !Select [1, !GetAZs ''] + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-public-2 + - Key: env + Value: !Ref env + - Key: Tier + Value: Public + + # Private Subnets - For ECS Services and RDS + PrivateSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PrivateSubnet1CIDR + AvailabilityZone: !Select [0, !GetAZs ''] + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-private-1 + - Key: env + Value: !Ref env + - Key: Tier + Value: Private + + PrivateSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PrivateSubnet2CIDR + AvailabilityZone: !Select [1, !GetAZs ''] + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-private-2 + - Key: env + Value: !Ref env + - Key: Tier + Value: Private + + NatGateway: + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt NatGatewayEIP.AllocationId + SubnetId: !Ref PublicSubnet1 + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-nat + - Key: env + Value: !Ref env + + PublicRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref SDPVPC + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-public-rt + - Key: env + Value: !Ref env + + PrivateRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref SDPVPC + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-private-rt + - Key: env + Value: !Ref env + + PublicRoute: + Type: AWS::EC2::Route + DependsOn: AttachGateway + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + PrivateRoute: + Type: AWS::EC2::Route + Properties: + RouteTableId: !Ref PrivateRouteTable + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref NatGateway + + PublicSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + SubnetId: !Ref PublicSubnet1 + RouteTableId: !Ref PublicRouteTable + + PublicSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + SubnetId: !Ref PublicSubnet2 + RouteTableId: !Ref PublicRouteTable + + PrivateSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + SubnetId: !Ref PrivateSubnet1 + RouteTableId: !Ref PrivateRouteTable + + PrivateSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + SubnetId: !Ref PrivateSubnet2 + RouteTableId: !Ref PrivateRouteTable + + PublicALB: + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + Properties: + Type: application + Scheme: internet-facing + SecurityGroups: + - !Ref PublicALBSecurityGroup + Subnets: + - !Ref PublicSubnet1 + - !Ref PublicSubnet2 + + PrivateALB: + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + Properties: + Type: application + Scheme: internal + SecurityGroups: + - !Ref PrivateALBSecurityGroup + Subnets: + - !Ref PrivateSubnet1 + - !Ref PrivateSubnet2 + + HTTPListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + LoadBalancerArn: !Ref PublicALB + Port: 80 + Protocol: HTTP + DefaultActions: + - Type: redirect + RedirectConfig: + Protocol: HTTPS + Port: '443' + StatusCode: HTTP_301 + + HTTPSListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + LoadBalancerArn: !Ref PublicALB + Port: 443 + Protocol: HTTPS + Certificates: + - CertificateArn: !Ref CertificateArn + DefaultActions: + - Type: fixed-response + FixedResponseConfig: + ContentType: text/plain + MessageBody: "Not Found" + StatusCode: 404 + + PrivateHTTPSListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + LoadBalancerArn: !Ref PrivateALB + Port: 443 + Protocol: HTTPS + Certificates: + - CertificateArn: !Ref CertificateArn + DefaultActions: + - Type: fixed-response + FixedResponseConfig: + ContentType: text/plain + MessageBody: "Not Found" + StatusCode: 404 + + # Public ALB Security Group + PublicALBSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for public ALB + VpcId: !Ref SDPVPC + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 80 + ToPort: 80 + CidrIp: 0.0.0.0/0 + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 + CidrIp: 0.0.0.0/0 + SecurityGroupEgress: + - IpProtocol: -1 + FromPort: -1 + ToPort: -1 + CidrIp: 0.0.0.0/0 + + PrivateALBSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for private ALB + VpcId: !Ref SDPVPC + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 + CidrIp: !Ref VPCCidr # Accept traffic from within VPC + SecurityGroupEgress: + - IpProtocol: -1 + FromPort: -1 + ToPort: -1 + CidrIp: 0.0.0.0/0 + + ECSServicesSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for ECS services + VpcId: !Ref SDPVPC + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 0 + ToPort: 65535 + SourceSecurityGroupId: !Ref PublicALBSecurityGroup + - IpProtocol: tcp + FromPort: 0 + ToPort: 65535 + CidrIp: !Ref VPCCidr # Accept traffic from within VPC + SecurityGroupEgress: + - IpProtocol: -1 + FromPort: -1 + ToPort: -1 + CidrIp: 0.0.0.0/0 + +Outputs: + + VPCId: + Description: VPC ID + Value: !Ref SDPVPC + Export: + Name: !Sub ${AWS::StackName}-vpc-id + + PublicSubnet1Id: + Description: Public Subnet 1 ID + Value: !Ref PublicSubnet1 + Export: + Name: !Sub ${AWS::StackName}-public-subnet-1 + + PublicSubnet2Id: + Description: Public Subnet 2 ID + Value: !Ref PublicSubnet2 + Export: + Name: !Sub ${AWS::StackName}-public-subnet-2 + + PrivateSubnet1Id: + Description: Private Subnet 1 ID + Value: !Ref PrivateSubnet1 + Export: + Name: !Sub ${AWS::StackName}-private-subnet-1 + + PrivateSubnet2Id: + Description: Private Subnet 2 ID + Value: !Ref PrivateSubnet2 + Export: + Name: !Sub ${AWS::StackName}-private-subnet-2 + + PublicALBDNSName: + Value: !GetAtt PublicALB.DNSName + Export: + Name: !Sub ${AWS::StackName}-public-alb-dns + + PrivateALBDNSName: + Value: !GetAtt PrivateALB.DNSName + Export: + Name: !Sub ${AWS::StackName}-private-alb-dns + + HTTPSListenerArn: + Value: !Ref HTTPSListener + Export: + Name: !Sub ${AWS::StackName}-https-listener-arn + + PrivateHTTPSListenerArn: + Value: !Ref PrivateHTTPSListener + Export: + Name: !Sub ${AWS::StackName}-private-https-listener-arn + + PublicALBSecurityGroupId: + Description: Public ALB Security Group ID + Value: !Ref PublicALBSecurityGroup + Export: + Name: !Sub ${AWS::StackName}-public-alb-sg + + PrivateALBSecurityGroupId: + Description: Private ALB Security Group ID + Value: !Ref PrivateALBSecurityGroup + Export: + Name: !Sub ${AWS::StackName}-private-alb-sg + + ECSServicesSecurityGroupId: + Description: ECS Services Security Group ID + Value: !Ref ECSServicesSecurityGroup + Export: + Name: !Sub ${AWS::StackName}-ecs-services-sg + + VPCCidr: + Description: VPC CIDR Block + Value: !Ref VPCCidr + Export: + Name: !Sub ${AWS::StackName}-vpc-cidr + + PublicALBHostedZoneID: + Value: !GetAtt PublicALB.CanonicalHostedZoneID + Export: + Name: !Sub ${AWS::StackName}-public-alb-hosted-zone + + PrivateALBHostedZoneID: + Value: !GetAtt PrivateALB.CanonicalHostedZoneID + Export: + Name: !Sub ${AWS::StackName}-private-alb-hosted-zone \ No newline at end of file diff --git a/resources/aws/cloudformation/sdp-network-eks.yaml b/resources/aws/cloudformation/sdp-network-eks.yaml new file mode 100644 index 000000000..cc8504471 --- /dev/null +++ b/resources/aws/cloudformation/sdp-network-eks.yaml @@ -0,0 +1,297 @@ +Parameters: + AWSRegion: + Type: String + Default: "us-west-1" + + env: + Type: String + Default: "dev" + AllowedValues: + - dev + - staging + - prod + + ExistingVPCId: + Type: String + Default: "" + Description: "If specified, use an existing VPC instead of creating a new one" + + ExistingPublicSubnet1Id: + Type: String + Default: "" + Description: "If using existing VPC, specify the first public subnet ID" + + ExistingPublicSubnet2Id: + Type: String + Default: "" + Description: "If using existing VPC, specify the second public subnet ID" + + ExistingPrivateSubnet1Id: + Type: String + Default: "" + Description: "If using existing VPC, specify the first private subnet ID" + + ExistingPrivateSubnet2Id: + Type: String + Default: "" + Description: "If using existing VPC, specify the second private subnet ID" + + VPCCidr: + Type: String + Default: "10.0.0.0/16" + + PublicSubnet1CIDR: + Type: String + Default: "10.0.0.0/24" + + PublicSubnet2CIDR: + Type: String + Default: "10.0.1.0/24" + + PrivateSubnet1CIDR: + Type: String + Default: "10.0.2.0/24" + + PrivateSubnet2CIDR: + Type: String + Default: "10.0.3.0/24" + +Conditions: + CreateNewVPC: !Equals + - !Ref ExistingVPCId + - "" + +Resources: + SDPVPC: + Type: AWS::EC2::VPC + Condition: CreateNewVPC + Properties: + CidrBlock: !Ref VPCCidr + EnableDnsHostnames: true + EnableDnsSupport: true + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-vpc + - Key: env + Value: !Ref env + + InternetGateway: + Type: AWS::EC2::InternetGateway + Condition: CreateNewVPC + Properties: + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-igw + - Key: env + Value: !Ref env + + AttachGateway: + Type: AWS::EC2::VPCGatewayAttachment + Condition: CreateNewVPC + Properties: + VpcId: !Ref SDPVPC + InternetGatewayId: !Ref InternetGateway + + # Public Subnets + PublicSubnet1: + Type: AWS::EC2::Subnet + Condition: CreateNewVPC + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PublicSubnet1CIDR + AvailabilityZone: !Sub ${AWS::Region}a + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-public-subnet-1 + - Key: env + Value: !Ref env + + PublicSubnet2: + Type: AWS::EC2::Subnet + Condition: CreateNewVPC + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PublicSubnet2CIDR + AvailabilityZone: !Sub ${AWS::Region}c + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-public-subnet-2 + - Key: env + Value: !Ref env + + # Private Subnets + PrivateSubnet1: + Type: AWS::EC2::Subnet + Condition: CreateNewVPC + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PrivateSubnet1CIDR + AvailabilityZone: !Sub ${AWS::Region}a + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-private-subnet-1 + - Key: env + Value: !Ref env + + PrivateSubnet2: + Type: AWS::EC2::Subnet + Condition: CreateNewVPC + Properties: + VpcId: !Ref SDPVPC + CidrBlock: !Ref PrivateSubnet2CIDR + AvailabilityZone: !Sub ${AWS::Region}c + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-private-subnet-2 + - Key: env + Value: !Ref env + + # NAT Gateway + NatGatewayEIP: + Type: AWS::EC2::EIP + Condition: CreateNewVPC + DependsOn: AttachGateway + Properties: + Domain: vpc + Tags: + - Key: env + Value: !Ref env + + NatGateway: + Type: AWS::EC2::NatGateway + Condition: CreateNewVPC + Properties: + AllocationId: !GetAtt NatGatewayEIP.AllocationId + SubnetId: !Ref PublicSubnet1 + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-nat-gateway + - Key: env + Value: !Ref env + + # Route Tables + PublicRouteTable: + Type: AWS::EC2::RouteTable + Condition: CreateNewVPC + Properties: + VpcId: !Ref SDPVPC + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-public-route-table + - Key: env + Value: !Ref env + + PrivateRouteTable: + Type: AWS::EC2::RouteTable + Condition: CreateNewVPC + Properties: + VpcId: !Ref SDPVPC + Tags: + - Key: Name + Value: !Sub ${env}-${AWS::StackName}-private-route-table + - Key: env + Value: !Ref env + + PublicRoute: + Type: AWS::EC2::Route + Condition: CreateNewVPC + DependsOn: AttachGateway + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + PrivateRoute: + Type: AWS::EC2::Route + Condition: CreateNewVPC + Properties: + RouteTableId: !Ref PrivateRouteTable + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref NatGateway + + # Subnet Route Table Associations + PublicSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Condition: CreateNewVPC + Properties: + SubnetId: !Ref PublicSubnet1 + RouteTableId: !Ref PublicRouteTable + + PublicSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Condition: CreateNewVPC + Properties: + SubnetId: !Ref PublicSubnet2 + RouteTableId: !Ref PublicRouteTable + + PrivateSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Condition: CreateNewVPC + Properties: + SubnetId: !Ref PrivateSubnet1 + RouteTableId: !Ref PrivateRouteTable + + PrivateSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Condition: CreateNewVPC + Properties: + SubnetId: !Ref PrivateSubnet2 + RouteTableId: !Ref PrivateRouteTable + +Outputs: + VPCId: + Description: VPC ID + Value: !If + - CreateNewVPC + - !Ref SDPVPC + - !Ref ExistingVPCId + Export: + Name: !Sub ${AWS::StackName}-vpc-id + + VPCCidr: + Description: VIPC CIDR + Value: !If + - CreateNewVPC + - !Ref VPCCidr + - !GetAtt SDPVPC.CidrBlock + Export: + Name: !Sub ${AWS::StackName}-vpc-cidr + + + PublicSubnet1: + Description: Public Subnet 1 ID + Value: !If + - CreateNewVPC + - !Ref PublicSubnet1 + - !Ref ExistingPublicSubnet1Id + Export: + Name: !Sub ${AWS::StackName}-public-subnet-1 + + PublicSubnet2: + Description: Public Subnet 2 ID + Value: !If + - CreateNewVPC + - !Ref PublicSubnet2 + - !Ref ExistingPublicSubnet2Id + Export: + Name: !Sub ${AWS::StackName}-public-subnet-2 + + PrivateSubnet1: + Description: Private Subnet 1 ID + Value: !If + - CreateNewVPC + - !Ref PrivateSubnet1 + - !Ref ExistingPrivateSubnet1Id + Export: + Name: !Sub ${AWS::StackName}-private-subnet-1 + + PrivateSubnet2: + Description: Private Subnet 2 ID + Value: !If + - CreateNewVPC + - !Ref PrivateSubnet2 + - !Ref ExistingPrivateSubnet2Id + Export: + Name: !Sub ${AWS::StackName}-private-subnet-2 \ No newline at end of file From 4b558cf17bbfc1c53ecc945eff8d7d4088b7e7cb Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Thu, 23 Jan 2025 13:18:56 -0800 Subject: [PATCH 02/11] remove recaptcha key --- resources/aws/cloudformation/sdp-ecs.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/aws/cloudformation/sdp-ecs.yaml b/resources/aws/cloudformation/sdp-ecs.yaml index f25e4ee7f..d35ebb1c3 100644 --- a/resources/aws/cloudformation/sdp-ecs.yaml +++ b/resources/aws/cloudformation/sdp-ecs.yaml @@ -387,7 +387,7 @@ - Name: USDC_ASSET_ISSUER Value: GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5 - Name: RECAPTCHA_SITE_KEY - Value: 6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb + Value: RECAPTCHA_SITE_KEY_VALUE - Name: SINGLE_TENANT_MODE Value: "false" - Name: PUBLIC_ALB_DNS @@ -1059,7 +1059,7 @@ Properties: Name: !Sub "/sdp/${env}/RECAPTCHA_SITE_SECRET_KEY" Type: String - Value: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" + Value: "RECAPTCHA_SITE_KEY_VALUE" Tags: env: !Ref env From 3b844b233f9d1be608c7d1d7ccaca9772d890a8c Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Fri, 24 Jan 2025 16:57:29 -0600 Subject: [PATCH 03/11] Reset .gitignore --- .gitignore | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 02e4ef67a..000000000 --- a/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Environment file -.env - -# subproject used for testing: -v1_compatibility/stellar-relief-backoffice-backend - -# Project binary: -stellar-disbursement-platform-backend - -# Text Editors -.vscode From 5d9221e8c556925faeda3137630bd92dca4fc175 Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Mon, 27 Jan 2025 14:14:49 -0800 Subject: [PATCH 04/11] made secrets more consistent --- resources/aws/cloudformation/README.md | 59 +- ...{sdp-secrets.yaml => sdp-secrets-dev.yaml} | 49 +- .../eks-helm/{values.yaml => values-dev.yaml} | 47 +- .../aws/cloudformation/sdp-database-eks.yaml | 8 +- resources/aws/cloudformation/sdp-eks.yaml | 37 +- .../aws/cloudformation/sdp-keys-eks.yaml | 541 ++++++++++++++++++ resources/aws/cloudformation/sdp-keys.yaml | 12 - 7 files changed, 652 insertions(+), 101 deletions(-) rename resources/aws/cloudformation/eks-helm/{sdp-secrets.yaml => sdp-secrets-dev.yaml} (60%) rename resources/aws/cloudformation/eks-helm/{values.yaml => values-dev.yaml} (78%) create mode 100644 resources/aws/cloudformation/sdp-keys-eks.yaml diff --git a/resources/aws/cloudformation/README.md b/resources/aws/cloudformation/README.md index d91efd07a..55049318b 100644 --- a/resources/aws/cloudformation/README.md +++ b/resources/aws/cloudformation/README.md @@ -9,20 +9,30 @@ This guide walks through deploying the Stellar Disbursement Platform (SDP) infrastructure on AWS. The deployment consists of four CloudFormation stacks that create the necessary infrastructure in a specific order: - Network Stack (sdp-network-eks.yaml) - - Creates or uses existing VPC and subnets Sets up networking for both public and private resources. Exports used (imported) by database and EKS stack to deploy resources. + - Creates or uses existing VPC and subnets + - Sets up networking for both public and private resources + - Exports used (imported) by database and EKS stack to deploy resources + - Database Stack (sdp-database-eks.yaml) - Deploys RDS PostgreSQL database in private subnet - - creates necessary database secrets in AWS Secrets Manager -- Keys Stack (sdp-keys.yaml) - - Manages Stellar keys and encryption secrets - - Provide keys as parameters or leave blank to auto-generate - - Stores all secrets in AWS Secrets Manager + - Creates necessary database secrets in AWS Secrets Manager + +- Keys Stack (sdp-keys.yaml) [Optional] + - Manages Stellar and encryption keys by either: + - Using provided keys via parameters, or + - Auto-generating keys using Lambda function for dev/test environments + - Stores all keys and secrets in AWS Secrets Manager under /sdp/${env}/ path + - Keys include SEP-10 signing keys, distribution account keys, JWT secrets, etc. + - EKS Stack (sdp-eks.yaml) - Creates EKS cluster and node group - Sets up IAM roles and security groups - - Configures necessary permissions for Kubernetes services -After the CloudFormation stacks are deployed, additional Kubernetes resources are installed via Helm charts to complete the setup. + - Configures IRSA (IAM Roles for Service Accounts) + - Sets up permissions for pods to access secrets stored in AWS Secrets Manager + +After the CloudFormation stacks are deployed, additional Kubernetes resources are installed via Helm charts to complete the setup. The SDP expects secrets to be available as Kubernetes secrets, but how those secrets are synchronized (whether through ExternalSecrets, direct creation, or other means) is left to the deployer's preference. +Note: Both the Keys stack and ExternalSecrets are optional implementation choices. You can manage and sync secrets to Kubernetes secrets through whatever mechanism best fits your security requirements and operational preferences. ##Verify AWS CLI Configuration ```bash aws configure list @@ -342,6 +352,39 @@ helm install sdp stellar/stellar-disbursement-platform \ kubectl -n sdp get pods ``` +## Security +The following outlines the security infrastructure implemented across the SDP stacks, including network access controls, IAM roles, and service accounts. +VPC Security Groups +- EKS Cluster Security Group +Purpose: Controls access to the EKS cluster control plane +Inbound Rules: +- Port 443 (HTTPS) from VPC CIDR +- All traffic from Node Security Group +Usage: Applied to EKS cluster control plane endpoints + +1. EKS Node Security Group + +Purpose: Controls access to EKS worker nodes +Inbound Rules: + +All traffic from EKS Cluster Security Group +All traffic from other nodes (self-referential) + + +Usage: Applied to all EKS worker nodes + +3. RDS Security Group + +Purpose: Controls access to PostgreSQL database +Inbound Rules: + +Port 5432 from EKS Cluster Security Group +Port 5432 from EKS Node Security Group +Port 5432 from EKS Created Security Group + + +Usage: Applied to RDS instance + ## Troubleshooting ### External Secrets Issues diff --git a/resources/aws/cloudformation/eks-helm/sdp-secrets.yaml b/resources/aws/cloudformation/eks-helm/sdp-secrets-dev.yaml similarity index 60% rename from resources/aws/cloudformation/eks-helm/sdp-secrets.yaml rename to resources/aws/cloudformation/eks-helm/sdp-secrets-dev.yaml index fdb27c0ff..025633d35 100644 --- a/resources/aws/cloudformation/eks-helm/sdp-secrets.yaml +++ b/resources/aws/cloudformation/eks-helm/sdp-secrets-dev.yaml @@ -14,70 +14,75 @@ spec: data: - secretKey: SECRET_DATA_USERNAME remoteRef: - key: /sdp/SECRET_DATA_USERNAME + key: /sdp/dev/SECRET_DATA_USERNAME - secretKey: SECRET_DATA_PASSWORD remoteRef: - key: /sdp/SECRET_DATA_PASSWORD + key: /sdp/dev/SECRET_DATA_PASSWORD - secretKey: DATA_SERVER remoteRef: - key: /sdp/DATA_SERVER + key: /sdp/dev/DATA_SERVER - secretKey: DISTRIBUTION_SEED remoteRef: - key: /sdp/DISTRIBUTION_SEED + key: /sdp/dev/DISTRIBUTION_SEED - secretKey: DISTRIBUTION_PUBLIC_KEY remoteRef: - key: /sdp/DISTRIBUTION_PUBLIC_KEY + key: /sdp/dev/DISTRIBUTION_PUBLIC_KEY - secretKey: SEP10_SIGNING_PRIVATE_KEY remoteRef: - key: /sdp/SEP10_SIGNING_PRIVATE_KEY + key: /sdp/dev/SEP10_SIGNING_PRIVATE_KEY - secretKey: SEP10_SIGNING_PUBLIC_KEY remoteRef: - key: /sdp/SEP10_SIGNING_PUBLIC_KEY + key: /sdp/dev/SEP10_SIGNING_PUBLIC_KEY - secretKey: SECRET_SEP10_SIGNING_SEED remoteRef: - key: /sdp/SECRET_SEP10_SIGNING_SEED + key: /sdp/dev/SECRET_SEP10_SIGNING_SEED - secretKey: EC256_PRIVATE_KEY remoteRef: - key: /sdp/EC256_PRIVATE_KEY + key: /sdp/dev/EC256_PRIVATE_KEY - secretKey: EC256_PUBLIC_KEY remoteRef: - key: /sdp/EC256_PUBLIC_KEY + key: /sdp/dev/EC256_PUBLIC_KEY - secretKey: CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE remoteRef: - key: /sdp/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE + key: /sdp/dev/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE - secretKey: DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE remoteRef: - key: /sdp/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE + key: /sdp/dev/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE - secretKey: SECRET_PLATFORM_API_AUTH_SECRET remoteRef: - key: /sdp/SECRET_PLATFORM_API_AUTH_SECRET + key: /sdp/dev/SECRET_PLATFORM_API_AUTH_SECRET - secretKey: SECRET_SEP10_JWT_SECRET remoteRef: - key: /sdp/SECRET_SEP10_JWT_SECRET + key: /sdp/dev/SECRET_SEP10_JWT_SECRET - secretKey: SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET remoteRef: - key: /sdp/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET + key: /sdp/dev/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET - secretKey: SECRET_SEP24_MORE_INFO_URL_JWT_SECRET remoteRef: - key: /sdp/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET + key: /sdp/dev/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET - secretKey: DATABASE_URL remoteRef: - key: /sdp/DATABASE_URL + key: /sdp/dev/DATABASE_URL - secretKey: SEP24_JWT_SECRET remoteRef: - key: /sdp/SEP24_JWT_SECRET + key: /sdp/dev/SEP24_JWT_SECRET - secretKey: ANCHOR_PLATFORM_OUTGOING_JWT_SECRET remoteRef: - key: /sdp/ANCHOR_PLATFORM_OUTGOING_JWT_SECRET + key: /sdp/dev/ANCHOR_PLATFORM_OUTGOING_JWT_SECRET - secretKey: RECAPTCHA_SITE_KEY remoteRef: - key: /sdp/RECAPTCHA_SITE_KEY + key: /sdp/dev/RECAPTCHA_SITE_KEY - secretKey: RECAPTCHA_SITE_SECRET_KEY remoteRef: - key: /sdp/RECAPTCHA_SITE_SECRET_KEY + key: /sdp/dev/RECAPTCHA_SITE_SECRET_KEY - secretKey: ADMIN_API_KEY remoteRef: - key: /sdp/ADMIN_API_KEY + key: /sdp/dev/ADMIN_API_KEY + + + + + diff --git a/resources/aws/cloudformation/eks-helm/values.yaml b/resources/aws/cloudformation/eks-helm/values-dev.yaml similarity index 78% rename from resources/aws/cloudformation/eks-helm/values.yaml rename to resources/aws/cloudformation/eks-helm/values-dev.yaml index eda190c8f..11b5b6e37 100644 --- a/resources/aws/cloudformation/eks-helm/values.yaml +++ b/resources/aws/cloudformation/eks-helm/values-dev.yaml @@ -30,15 +30,16 @@ sdp: secretName: sdp-secrets create: false data: - EC256_PRIVATE_KEY: "{{ .Release.Namespace }}/EC256_PRIVATE_KEY" - EC256_PUBLIC_KEY: "{{ .Release.Namespace }}/EC256_PUBLIC_KEY" - SEP10_SIGNING_PRIVATE_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" - SEP10_SIGNING_PUBLIC_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PUBLIC_KEY" - DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" - DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" - DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" - CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/channel-encryption-passphrase" - DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" + EC256_PRIVATE_KEY: "/dev/sdp/EC256_PRIVATE_KEY" + EC256_PUBLIC_KEY: "/dev/sdp/EC256_PUBLIC_KEY" + SEP10_SIGNING_PRIVATE_KEY: "/dev/sdp/SEP10_SIGNING_PRIVATE_KEY" + SEP10_SIGNING_PUBLIC_KEY: "/dev/sdp/SEP10_SIGNING_PUBLIC_KEY" + SEP24_JWT_SECRRET: "/dev/sdp/SEP24_JWT_SECRET" + DISTRIBUTION_SEED: "/dev/sdp/DISTRIBUTION_SEED" + DISTRIBUTION_PUBLIC_KEY: "/dev/sdp/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/channel-encryption-passphrase" + DATABASE_URL: "/dev/sdp/DATABASE_URL" # =========================== START sdp.configMap =========================== configMap: data: @@ -87,15 +88,15 @@ anchorPlatform: create: false secretName: sdp-secrets data: - SECRET_DATA_USERNAME: "{{ .Release.Namespace }}/SECRET_DATA_USERNAME" - SECRET_DATA_PASSWORD: "{{ .Release.Namespace }}/SECRET_DATA_PASSWORD" - DATA_SERVER: "{{ .Release.Namespace }}/DATA_SERVER" - SECRET_SEP10_SIGNING_SEED: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" - SECRET_PLATFORM_API_AUTH_SECRET: "{{ .Release.Namespace }}/SECRET_PLATFORM_API_AUTH_SECRET" - SECRET_SEP10_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP10_JWT_SECRET" - SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" - SECRET_SEP24_MORE_INFO_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" - DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" + SECRET_DATA_USERNAME: "/dev/sdp/SECRET_DATA_USERNAME" + SECRET_DATA_PASSWORD: "/dev/sdp/SECRET_DATA_PASSWORD" + DATA_SERVER: "/dev/sdp/DATA_SERVER" + SECRET_SEP10_SIGNING_SEED: "/dev/sdp/SEP10_SIGNING_PRIVATE_KEY" + SECRET_PLATFORM_API_AUTH_SECRET: "/dev/sdp/SECRET_PLATFORM_API_AUTH_SECRET" + SECRET_SEP10_JWT_SECRET: "/dev/sdp/SECRET_SEP10_JWT_SECRET" + SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET: "/dev/sdp/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" + SECRET_SEP24_MORE_INFO_URL_JWT_SECRET: "/dev/sdp/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" + DISTRIBUTION_PUBLIC_KEY: "/dev/sdp/DISTRIBUTION_PUBLIC_KEY" serviceAccount: create: true name: anchor-service-account @@ -189,11 +190,11 @@ tss: create: false secretName: sdp-secrets data: - DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" - DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" - DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" - CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" - DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" + DISTRIBUTION_PUBLIC_KEY: "/dev/sdp/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_SEED: "/dev/sdp/DISTRIBUTION_SEED" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" + DATABASE_URL: "/dev/sdp/DATABASE_URL" serviceAccount: create: true name: tss-service-account diff --git a/resources/aws/cloudformation/sdp-database-eks.yaml b/resources/aws/cloudformation/sdp-database-eks.yaml index fd14f98e2..1fbfb32a9 100644 --- a/resources/aws/cloudformation/sdp-database-eks.yaml +++ b/resources/aws/cloudformation/sdp-database-eks.yaml @@ -133,28 +133,28 @@ Resources: SecretDataUsernameSecret: Type: AWS::SecretsManager::Secret Properties: - Name: !Sub /${namespace}/SECRET_DATA_USERNAME + Name: !Sub /${namespace}/${env}/SECRET_DATA_USERNAME Description: Anchor Platform DATA_USER SecretString: !Ref DBUsername SecretDataPasswordSecret: Type: AWS::SecretsManager::Secret Properties: - Name: !Sub /${namespace}/SECRET_DATA_PASSWORD + Name: !Sub /${namespace}/${env}/SECRET_DATA_PASSWORD Description: Anchor Platform SECRET_DATA_PASSWORD SecretString: !Ref DBPassword DataServerSecret: Type: AWS::SecretsManager::Secret Properties: - Name: !Sub /${namespace}/DATA_SERVER + Name: !Sub /${namespace}/${env}/DATA_SERVER Description: Anchor Platform DATA_SERVER SecretString: !GetAtt PostgresInstance.Endpoint.Address DatabaseURLSecret: Type: AWS::SecretsManager::Secret Properties: - Name: !Sub /${namespace}/DATABASE_URL + Name: !Sub /${namespace}/${env}/DATABASE_URL Description: Complete database connection URL SecretString: !Sub "postgres://${DBUsername}:${DBPassword}@${PostgresInstance.Endpoint.Address}:${PostgresInstance.Endpoint.Port}/sdp_${env}" diff --git a/resources/aws/cloudformation/sdp-eks.yaml b/resources/aws/cloudformation/sdp-eks.yaml index 004bd8535..93143d7cc 100644 --- a/resources/aws/cloudformation/sdp-eks.yaml +++ b/resources/aws/cloudformation/sdp-eks.yaml @@ -18,12 +18,7 @@ Parameters: DatabaseStackName: Type: String Default: sdp-database - Description: Name of the database stack - - KeysStackName: - Type: String - Default: sdp-keys - Description: Name of the keys/secrets stack + Description: Name of the database stack used to create security group Resources: ######################################################################## @@ -161,11 +156,7 @@ Resources: Action: - secretsmanager:GetSecretValue Resource: - - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn - - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret + - !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/* ExternalDNSPolicy: Type: AWS::IAM::ManagedPolicy @@ -338,14 +329,7 @@ Resources: - 'secretsmanager:GetSecretValue' - 'secretsmanager:DescribeSecret' Resource: - - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/${env}/*" - - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/*" - - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn - - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret - - Fn::ImportValue: !Sub ${DatabaseStackName}-db-secret-arn + - !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/* SDPServiceAccountRole: Type: AWS::IAM::Role @@ -383,11 +367,7 @@ Resources: Action: - secretsmanager:GetSecretValue Resource: - - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn - - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret + - !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/* ClusterOIDCIdFunction: Type: AWS::Lambda::Function @@ -485,14 +465,7 @@ Resources: - 'secretsmanager:GetSecretValue' - 'secretsmanager:DescribeSecret' Resource: - - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/${env}/*" - - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/*" - - Fn::ImportValue: !Sub ${KeysStackName}-sep10-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-distribution-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-channel-secret-arn - - Fn::ImportValue: !Sub ${KeysStackName}-ec256-secret-arn - - Fn::ImportValue: !Sub ${DatabaseStackName}-database-url-secret - - Fn::ImportValue: !Sub ${DatabaseStackName}-db-secret-arn + - !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/sdp/* Outputs: ClusterName: diff --git a/resources/aws/cloudformation/sdp-keys-eks.yaml b/resources/aws/cloudformation/sdp-keys-eks.yaml new file mode 100644 index 000000000..51fab0442 --- /dev/null +++ b/resources/aws/cloudformation/sdp-keys-eks.yaml @@ -0,0 +1,541 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Stack for managing Stellar and encryption keys in Secrets Manager for ECS' + +Parameters: + env: + Type: String + Default: "dev" + Description: "Environment variable: ENV" + + namespace: + Type: String + Description: "Environment variable: namespace - Kubernetes namespace where SDP will be deployed" + Default: "sdp" + + StellarLayerS3Bucket: + Type: String + Description: "S3 bucket containing the Stellar SDK Lambda layer" + Default: "stellar-layer" + + Sep10SigningPrivateKey: + Type: String + Default: "" + NoEcho: true + Description: "Environment variable: SEP10_SIGNING_PRIVATE_KEY" + + SecretSep10SigningSeed: + Type: String + Default: "" + NoEcho: true + Description: "Environment variable: Anchor Platform SECRET_SEP10_SIGNING_SEED" + + Sep10SigningPublicKey: + Type: String + Default: "" + Description: "Environment variable: SEP10_SIGNING_PUBLIC_KEY" + + SecretSep10JwtSecret: + Type: String + NoEcho: true + Default: "jwt_secret_1234567890" + Description: "Environment variable: SECRET_SEP10_JWT_SECRET" + + DistributionSeed: + Type: String + Default: "" + NoEcho: true + Description: "Environment variable: DISTRIBUTION_SEED" + + DistributionPublicKey: + Type: String + Default: "" + Description: "Environment variable: DISTRIBUTION_PUBLIC_KEY" + + DistributionAccountEncryptionPassphrase: + Type: String + Default: "" + NoEcho: true + Description: "Environment variable: DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + + ChannelAccountEncryptionPassphrase: + Type: String + Default: "" + NoEcho: true + Description: "Environment variable: CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" + + Ec256PrivateKey: + Type: String + NoEcho: true + Default: | + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIPRRtyc5EQoNPFhkcDzC47B2Zpo5b0NiM3Ftvky86+bEoAoGCCqGSM49 + AwEHoUQDQgAEWinhVw0QHkZDeZ777zfBKT0cupULkpEd8Y52iPs76AT7JQ1cuGbm + jxJASNwp907KzNzOZJSV07bFdN/Tkwebgg== + -----END EC PRIVATE KEY----- + Description: "Environment variable: EC256_PRIVATE_KEY" + + Ec256PublicKey: + Type: String + Default: | + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWinhVw0QHkZDeZ777zfBKT0cupUL + kpEd8Y52iPs76AT7JQ1cuGbmjxJASNwp907KzNzOZJSV07bFdN/Tkwebgg== + -----END PUBLIC KEY----- + Description: "Environment variable: EC256_PUBLIC_KEY" + + SecretSep24InteractiveUrlJwtSecret: + Type: String + NoEcho: true + Default: "jwt_secret_1234567890" + Description: "Environment variable: SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" + + SecretSep24MoreInfoUrlJwtSecret: + Type: String + NoEcho: true + Default: "jwt_secret_1234567890" + Description: "Environment variable: SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" + + Sep24JwtSecret: + Type: String + NoEcho: true + Default: "jwt_secret_1234567890" + Description: "Environment variable: SEP24_JWT_SECRET" + + SecretPlatformApiAuthSecret: + Type: String + NoEcho: true + Default: "platform-api-auth-secret" + Description: "Environment varible SECRET_PLATFORM_API_AUTH_SECRET" + + AnchorPlatformOutgoingJwtSecret: + Type: String + NoEcho: true + Default: "jwt_secret_1234567890" + Description: "Environment variable: ANCHOR_PLATFORM_OUTGOING_JWT_SECRET" + + AdminApiKey: + Type: String + NoEcho: true + Default: "admin-api-key" + Description: "Environment variable: ADMIN_API_KEY" + + RecaptchaSiteKey: + Type: String + NoEcho: true + Default: "YOUR_RECAPTCHA_KEY" + Description: "Environment variable: RECAPTCHA_SITE_KEY" + +Conditions: + GenerateSep10Keys: !Equals [ !Ref Sep10SigningPrivateKey, "" ] + GenerateDistributionKeys: !Equals [ !Ref DistributionSeed, "" ] + GenerateChannelKeys: !Equals [ !Ref ChannelAccountEncryptionPassphrase, "" ] + +Resources: + StellarKeyGenRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: SecretsManagerAccess + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - secretsmanager:CreateSecret + - secretsmanager:PutSecretValue + - secretsmanager:UpdateSecret + Resource: + - !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/${env}/*' + + StellarKeyGenRolePolicy: + Type: AWS::IAM::Policy + Properties: + PolicyName: !Sub ${AWS::StackName}-stellar-keygen-policy + Roles: + - !Ref StellarKeyGenRole + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + Resource: + - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*" + + StellarSDKLayer: + Type: AWS::Lambda::LayerVersion + Properties: + LayerName: stellar-sdk-layer + Content: + S3Bucket: !Ref StellarLayerS3Bucket + S3Key: stellar-layer.zip + CompatibleRuntimes: + - nodejs18.x + + StellarKeyGenFunction: + Type: AWS::Lambda::Function + Properties: + Runtime: nodejs18.x + Handler: index.handler + Role: !GetAtt StellarKeyGenRole.Arn + Timeout: 30 + Layers: + - !Ref StellarSDKLayer + Code: + ZipFile: | + const { Keypair } = require('@stellar/stellar-sdk'); + const https = require('https'); + const url = require('url'); + + async function fundTestnetAccount(publicKey) { + return new Promise((resolve, reject) => { + https.get(`https://friendbot.stellar.org?addr=${publicKey}`, (resp) => { + let data = ''; + resp.on('data', (chunk) => data += chunk); + resp.on('end', () => { + console.log('Funding response:', data); + resolve(data); + }); + }).on('error', (err) => { + console.error('Error funding account:', err); + reject(err); + }); + }); + } + + function sendResponse(event, response) { + return new Promise((resolve, reject) => { + const parsedUrl = url.parse(event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + port: 443, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'Content-Type': '', + 'Content-Length': Buffer.byteLength(JSON.stringify(response)) + } + }; + + const request = https.request(requestOptions, (resp) => { + resolve(); + }); + + request.on('error', (error) => { + console.error('Error sending response:', error); + reject(error); + }); + + request.write(JSON.stringify(response)); + request.end(); + }); + } + + exports.handler = async (event, context) => { + try { + let response = { + Status: 'SUCCESS', + RequestId: event.RequestId, + LogicalResourceId: event.LogicalResourceId, + StackId: event.StackId, + PhysicalResourceId: context.logStreamName + }; + + if (event.RequestType === 'Delete') { + console.log('Delete request, sending success response'); + } else { + console.log('Generating new keypair'); + const pair = Keypair.random(); + response.Data = { + publicKey: pair.publicKey(), + secretKey: pair.secret() + }; + + if (event.ResourceProperties.KeyPairId === 'distribution') { + console.log('Funding distribution account on testnet'); + try { + await fundTestnetAccount(pair.publicKey()); + console.log('Successfully funded account'); + } catch (fundError) { + console.error('Error funding account:', fundError); + } + } + } + + await sendResponse(event, response); + return response; + + } catch (error) { + console.error('Error:', error); + const response = { + Status: 'FAILED', + RequestId: event.RequestId, + LogicalResourceId: event.LogicalResourceId, + StackId: event.StackId, + PhysicalResourceId: context.logStreamName, + Reason: error.toString() + }; + await sendResponse(event, response); + return response; + } + }; + + Sep10KeyGenPair: + Type: Custom::StellarKeyPair + Condition: GenerateSep10Keys + Properties: + ServiceToken: !GetAtt StellarKeyGenFunction.Arn + KeyPairId: sep10 + + DistributionKeyGenPair: + Type: Custom::StellarKeyPairx + Condition: GenerateDistributionKeys + Properties: + ServiceToken: !GetAtt StellarKeyGenFunction.Arn + KeyPairId: distribution + + ChannelKeyGenPair: + Type: Custom::StellarKeyPair + Condition: GenerateChannelKeys + Properties: + ServiceToken: !GetAtt StellarKeyGenFunction.Arn + KeyPairId: channel + + Sep10SigningPrivateKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SEP10_SIGNING_PRIVATE_KEY + Description: "SEP10 signing private key" + SecretString: !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.secretKey, !Ref Sep10SigningPrivateKey] + + SecretSep10SigningSeedSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SECRET_SEP10_SIGNING_SEED + Description: "SEP10 signing private key" + SecretString: !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.secretKey, !Ref Sep10SigningPrivateKey] + + Sep10SigningPublicKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SEP10_SIGNING_PUBLIC_KEY + Description: "SEP10 signing public key" + SecretString: !If [GenerateSep10Keys, !GetAtt Sep10KeyGenPair.publicKey, !Ref Sep10SigningPublicKey] + + SecretSep10JwtSecretSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SECRET_SEP10_JWT_SECRET + Description: "SECRET_SEP10_JWT_SECRET" + SecretString: !Ref SecretSep10JwtSecret + + DistributionSeedSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/DISTRIBUTION_SEED + Description: "Distribution account seed" + SecretString: !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.secretKey, !Ref DistributionSeed] + + DistributionPublicKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/DISTRIBUTION_PUBLIC_KEY + Description: "Distribution account public key" + SecretString: !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.publicKey, !Ref DistributionPublicKey] + + DistributionEncryptionPassphraseSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE + Description: "Distribution account encryption passphrase" + SecretString: !If [GenerateDistributionKeys, !GetAtt DistributionKeyGenPair.secretKey, !Ref DistributionAccountEncryptionPassphrase] + + ChannelEncryptionPassphraseSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE + Description: "Channel account encryption passphrase" + SecretString: !If [GenerateChannelKeys, !GetAtt ChannelKeyGenPair.secretKey, !Ref ChannelAccountEncryptionPassphrase] + + Ec256PrivateKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/EC256_PRIVATE_KEY + Description: "EC256 private key" + SecretString: !Ref Ec256PrivateKey + + Ec256PublicKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/EC256_PUBLIC_KEY + Description: "EC256 public key" + SecretString: !Ref Ec256PublicKey + + SecretSep24InteractiveUrlJwtSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET + Description: "SEP24 interactive URL JWT secret" + SecretString: !Ref SecretSep24InteractiveUrlJwtSecret + + SecretSep24MoreInfoUrlJwtSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET + Description: "SEP24 more info URL JWT secret" + SecretString: !Ref SecretSep24MoreInfoUrlJwtSecret + + Sep24JwtSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SEP24_JWT_SECRET + Description: "SEP24 JWT secret" + SecretString: !Ref Sep24JwtSecret + + SecretPlatformApiAuthSecretSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/SECRET_PLATFORM_API_AUTH_SECRET + SecretString: !Ref AnchorPlatformOutgoingJwtSecret + + AnchorPlatformOutgoingJwtSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/ANCHOR_PLATFORM_OUTGOING_JWT_SECRET + Description: "Anchor platform outgoing JWT secret" + SecretString: !Ref SecretPlatformApiAuthSecret + + AdminApiKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/ADMIN_API_KEY + Description: "Admin API key" + SecretString: !Ref AdminApiKey + + RecaptchaSiteKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/RECAPTCHA_SITE_KEY + Description: "Recaptcha site key" + SecretString: !Ref RecaptchaSiteKey + + RecaptchaSiteSecretKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/RECAPTCHA_SITE_SECRET_KEY + Description: "Recaptcha site secret key" + SecretString: !Ref RecaptchaSiteKey + +Outputs: + Sep10SigningPrivateKeySmArn: + Value: !Ref Sep10SigningPrivateKeySm + Export: + Name: !Sub ${AWS::StackName}-sep10-signing-private-key-sm-arn + Description: "ARN for SEP10_SIGNING_PRIVATE_KEY secret" + + Sep10SigningPublicKeySmArn: + Value: !Ref Sep10SigningPublicKeySm + Export: + Name: !Sub ${AWS::StackName}-sep10-signing-public-key-sm-arn + Description: "ARN for SEP10_SIGNING_PUBLIC_KEY secret" + + SecretSep10JwtSecretSmArn: + Value: !Ref SecretSep10JwtSecretSm + Export: + Name: !Sub ${AWS::StackName}-sep10-jwt-secret-key-sm-arn + Description: "ARN for SEP10_JWT_SECRET secret" + + DistributionSeedSmArn: + Value: !Ref DistributionSeedSm + Export: + Name: !Sub ${AWS::StackName}-distribution-seed-sm-arn + Description: "ARN for DISTRIBUTION_SEED secret" + + DistributionPublicKeySmArn: + Value: !Ref DistributionPublicKeySm + Export: + Name: !Sub ${AWS::StackName}-distribution-public-key-sm-arn + Description: "ARN for DISTRIBUTION_PUBLIC_KEY secret" + + DistributionEncryptionPassphraseSmArn: + Value: !Ref DistributionEncryptionPassphraseSm + Export: + Name: !Sub ${AWS::StackName}-distribution-encryption-passphrase-sm-arn + Description: "ARN for DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE secret" + + ChannelEncryptionPassphraseSmArn: + Value: !Ref ChannelEncryptionPassphraseSm + Export: + Name: !Sub ${AWS::StackName}-channel-encryption-passphrase-sm-arn + Description: "ARN for CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE secret" + + Ec256PrivateKeySmArn: + Value: !Ref Ec256PrivateKeySm + Export: + Name: !Sub ${AWS::StackName}-ec256-private-key-sm-arn + Description: "ARN for EC256_PRIVATE_KEY secret" + + Ec256PublicKeySmArn: + Value: !Ref Ec256PublicKeySm + Export: + Name: !Sub ${AWS::StackName}-ec256-public-key-sm-arn + Description: "ARN for EC256_PUBLIC_KEY secret" + + SecretSep24InteractiveUrlJwtSmArn: + Value: !Ref SecretSep24InteractiveUrlJwtSm + Export: + Name: !Sub ${AWS::StackName}-sep24-interactive-url-jwt-sm-arn + Description: "ARN for SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET secret" + + SecretSep24MoreInfoUrlJwtSmArn: + Value: !Ref SecretSep24MoreInfoUrlJwtSm + Export: + Name: !Sub ${AWS::StackName}-sep24-more-info-url-jwt-sm-arn + Description: "ARN for SECRET_SEP24_MORE_INFO_URL_JWT_SECRET secret" + + Sep24JwtSmArn: + Value: !Ref Sep24JwtSm + Export: + Name: !Sub ${AWS::StackName}-sep24-jwt-sm-arn + Description: "ARN for SEP24_JWT_SECRET secret" + + SecretPlatformApiAuthSecretArn: + Value: !Ref SecretPlatformApiAuthSecret + Export: + Name: !Sub ${AWS::StackName}-secret-platform-api-auth-secret-sm-arn + Description: "ARN for SECRET_PLATFORM_API_AUTH_SECRET " + + AnchorPlatformOutgoingJwtSmArn: + Value: !Ref AnchorPlatformOutgoingJwtSm + Export: + Name: !Sub ${AWS::StackName}-anchor-platform-outgoing-jwt-sm-arn + Description: "ARN for ANCHOR_PLATFORM_OUTGOING_JWT_SECRET secret" + + AdminApiKeySmArn: + Value: !Ref AdminApiKeySm + Export: + Name: !Sub ${AWS::StackName}-admin-api-key-sm-arn + Description: "ARN for ADMIN_API_KEY secret" + + RecaptchaSiteKeySmArn: + Value: !Ref RecaptchaSiteKeySm + Export: + Name: !Sub ${AWS::StackName}-recaptcha-site-key-sm-arn + Description: "ARN for RECAPTCHA_SITE_KEY secret" + + RecaptchaSiteSecretKeySmArn: + Value: !Ref RecaptchaSiteSecretKeySm + Export: + Name: !Sub ${AWS::StackName}-recaptcha-site-secret-key-sm-arn + Description: "ARN for RECAPTCHA_SITE_SECRET_KEY secret" \ No newline at end of file diff --git a/resources/aws/cloudformation/sdp-keys.yaml b/resources/aws/cloudformation/sdp-keys.yaml index 84f9f3c6e..28a14fbf0 100644 --- a/resources/aws/cloudformation/sdp-keys.yaml +++ b/resources/aws/cloudformation/sdp-keys.yaml @@ -397,12 +397,6 @@ Resources: Properties: Name: !Sub /${namespace}/ANCHOR_PLATFORM_OUTGOING_JWT_SECRET SecretString: "jwt_secret_1234567890" - - RecaptchaSiteKey: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /${namespace}/RECAPTCHA_SITE_KEY - SecretString: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" RecaptchaSiteSecretKey: Type: AWS::SecretsManager::Secret @@ -410,12 +404,6 @@ Resources: Name: !Sub /sdp/${env}/recaptcha-site-secret-key Description: "Recaptcha site secret key" SecretString: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" - - RecaptchaSiteSecretKeyEKS: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /sdp/RECAPTCHA_SITE_SECRET_KEY - SecretString: "6Lcw864qAAAAAJCtS-7NSSbu-iRX2ZS8iu4xUGIc" AdminApiKey: Type: AWS::SecretsManager::Secret From fe4bad6ce7738545874e16735d407bfb2db5a133 Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Tue, 28 Jan 2025 10:25:03 -0800 Subject: [PATCH 05/11] small fixes --- resources/aws/cloudformation/README.md | 12 ++++-------- .../aws/cloudformation/eks-helm/values-dev.yaml | 16 ++++++++++------ resources/aws/cloudformation/sdp-keys-eks.yaml | 10 ++++++++-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/resources/aws/cloudformation/README.md b/resources/aws/cloudformation/README.md index 55049318b..78d709400 100644 --- a/resources/aws/cloudformation/README.md +++ b/resources/aws/cloudformation/README.md @@ -1,4 +1,4 @@ -# # Stellar Disbursement Platform (SDP) Kubernetes Deployment Guide +# # Stellar Disbursement Platform (SDP) AWS Kubernetes (EKS) Deployment Guide ## Prerequisites - AWS CLI installed and configured @@ -47,10 +47,7 @@ aws cloudformation create-stack \ --stack-name sdp-network \ --template-body file://sdp-network-eks.yaml \ --parameters \ - ParameterKey=env,ParameterValue=dev \ - ParameterKey=AWSRegion,ParameterValue=us-west-2 \ - ParameterKey=ExistingVPCId,ParameterValue="" \ - ParameterKey=VPCCidr,ParameterValue="10.0.0.0/16" + ParameterKey=env,ParameterValue=dev ``` **Note**: To use existing network resources, provide the VPC and subnet IDs: @@ -99,7 +96,7 @@ Deploy the secrets and keys management stack: ```bash aws cloudformation create-stack \ - --stack-name sdp-keys \ + --stack-name sdp-keys-eks \ --template-body file://sdp-keys.yaml \ --capabilities CAPABILITY_NAMED_IAM \ --parameters \ @@ -131,8 +128,7 @@ aws cloudformation create-stack \ --parameters \ ParameterKey=env,ParameterValue=dev \ ParameterKey=NetworkStackName,ParameterValue=sdp-network \ - ParameterKey=DatabaseStackName,ParameterValue=sdp-database \ - ParameterKey=KeysStackName,ParameterValue=sdp-keys + ParameterKey=DatabaseStackName,ParameterValue=sdp-database ``` Wait for stack completion (this will take ~15-20 minutes): diff --git a/resources/aws/cloudformation/eks-helm/values-dev.yaml b/resources/aws/cloudformation/eks-helm/values-dev.yaml index 11b5b6e37..8fec64d3c 100644 --- a/resources/aws/cloudformation/eks-helm/values-dev.yaml +++ b/resources/aws/cloudformation/eks-helm/values-dev.yaml @@ -34,12 +34,14 @@ sdp: EC256_PUBLIC_KEY: "/dev/sdp/EC256_PUBLIC_KEY" SEP10_SIGNING_PRIVATE_KEY: "/dev/sdp/SEP10_SIGNING_PRIVATE_KEY" SEP10_SIGNING_PUBLIC_KEY: "/dev/sdp/SEP10_SIGNING_PUBLIC_KEY" - SEP24_JWT_SECRRET: "/dev/sdp/SEP24_JWT_SECRET" + SEP24_JWT_SECRET: "/dev/sdp/SEP24_JWT_SECRET" DISTRIBUTION_SEED: "/dev/sdp/DISTRIBUTION_SEED" DISTRIBUTION_PUBLIC_KEY: "/dev/sdp/DISTRIBUTION_PUBLIC_KEY" DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/channel-encryption-passphrase" DATABASE_URL: "/dev/sdp/DATABASE_URL" + RECAPTCHA_SITE_KEY: "/sdp/dev/RECAPTCHA_SITE_KEY" + RECAPTCHA_SITE_SECRET_KEY: "/sdp/dev/RECAPTCHA_SITE_SECRET_KEY" # =========================== START sdp.configMap =========================== configMap: data: @@ -136,7 +138,7 @@ anchorPlatform: "schema": "stellar", "code": "USDC", "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - "distribution_account": "GCIA55CO7M7VJNDMQYEJKP4WQRB45CL2RJYPDW64PD2X7VDOZS53A4KK", + "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", "significant_decimals": 7, "deposit": { "enabled": true, @@ -150,8 +152,8 @@ anchorPlatform: { "sep24_enabled": true, "schema": "stellar", - "code": "XLM", - "distribution_account": "${DISTRIBUTION_PUBLIC_KEY}", + "code": "native", + "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", "significant_decimals": 7, "deposit": { "enabled": true, @@ -225,9 +227,11 @@ dashboard: rollingUpdate: maxUnavailable: 0 maxSurge: 1 - configMap: + kubeSecrets: + create: false + secretName: sdp-secrets data: - RECAPTCHA_SITE_KEY: "6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb" + RECAPTCHA_SITE_KEY: "/sdp/dev/RECAPTCHA_SITE_KEY" ingress: enabled: true className: "ingress-public" diff --git a/resources/aws/cloudformation/sdp-keys-eks.yaml b/resources/aws/cloudformation/sdp-keys-eks.yaml index 51fab0442..027c52548 100644 --- a/resources/aws/cloudformation/sdp-keys-eks.yaml +++ b/resources/aws/cloudformation/sdp-keys-eks.yaml @@ -104,7 +104,7 @@ Parameters: SecretPlatformApiAuthSecret: Type: String NoEcho: true - Default: "platform-api-auth-secret" + Default: "jwt_secret_1234567890" Description: "Environment varible SECRET_PLATFORM_API_AUTH_SECRET" AnchorPlatformOutgoingJwtSecret: @@ -125,6 +125,12 @@ Parameters: Default: "YOUR_RECAPTCHA_KEY" Description: "Environment variable: RECAPTCHA_SITE_KEY" + RecaptchaSiteSecretKey: + Type: String + NoEcho: true + Default: "YOUR_RECAPTCHA_SECRET_KEY" + Description: "Environment variable: RECAPTCHA_SITE_SECRET_KEY" + Conditions: GenerateSep10Keys: !Equals [ !Ref Sep10SigningPrivateKey, "" ] GenerateDistributionKeys: !Equals [ !Ref DistributionSeed, "" ] @@ -435,7 +441,7 @@ Resources: Properties: Name: !Sub /sdp/${env}/RECAPTCHA_SITE_SECRET_KEY Description: "Recaptcha site secret key" - SecretString: !Ref RecaptchaSiteKey + SecretString: !Ref RecaptchaSiteSecretKey Outputs: Sep10SigningPrivateKeySmArn: From a9fd527a03e8ae0e3a40c7b844828f3064362921 Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Tue, 28 Jan 2025 13:46:47 -0800 Subject: [PATCH 06/11] final updates --- resources/aws/cloudformation/README.md | 91 ++++--- .../cloudformation/eks-helm/helm-values.yaml | 239 ------------------ .../cloudformation/eks-helm/values-dev.yaml | 63 ++--- 3 files changed, 86 insertions(+), 307 deletions(-) delete mode 100644 resources/aws/cloudformation/eks-helm/helm-values.yaml diff --git a/resources/aws/cloudformation/README.md b/resources/aws/cloudformation/README.md index 78d709400..311cb8b7d 100644 --- a/resources/aws/cloudformation/README.md +++ b/resources/aws/cloudformation/README.md @@ -264,7 +264,7 @@ kubectl get secretstore aws-backend -n sdp ## 3. Create External Secrets ```bash -kubectl apply -n sdp -f eks/helm/sdp-secrets.yaml +kubectl apply -n sdp -f eks-helm/sdp-secrets-dev.yaml kubectl get externalsecret sdp-secrets -n sdp ``` @@ -335,51 +335,64 @@ kubectl get pods -n external-dns ``` ## 7. Deploy SDP Helm Chart + +### Add Stellar Repository ```bash -# Add Stellar repository helm repo add stellar https://helm.stellar.org - -# Install SDP -helm install sdp stellar/stellar-disbursement-platform \ - -f eks-helm/values.yaml \ - --namespace sdp - -# Verify deployment -kubectl -n sdp get pods ``` -## Security -The following outlines the security infrastructure implemented across the SDP stacks, including network access controls, IAM roles, and service accounts. -VPC Security Groups -- EKS Cluster Security Group -Purpose: Controls access to the EKS cluster control plane -Inbound Rules: -- Port 443 (HTTPS) from VPC CIDR -- All traffic from Node Security Group -Usage: Applied to EKS cluster control plane endpoints - -1. EKS Node Security Group - -Purpose: Controls access to EKS worker nodes -Inbound Rules: - -All traffic from EKS Cluster Security Group -All traffic from other nodes (self-referential) - - -Usage: Applied to all EKS worker nodes - -3. RDS Security Group - -Purpose: Controls access to PostgreSQL database -Inbound Rules: +### Update your Values file with the Distribution Account Public Key +replace `YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY` with the distribution account public key stored in Secrets Manager + +```yaml +ASSETS_VALUE: | + { + "assets": [ + { + "sep24_enabled": true, + "schema": "stellar", + "code": "USDC", + "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + }, + { + "sep24_enabled": true, + "schema": "stellar", + "code": "native", + "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", + "significant_decimals": 7, + "deposit": { + "enabled": true, + "fee_minimum": 0, + "fee_percent": 0, + "min_amount": 1, + "max_amount": 10000 + }, + "withdraw": {"enabled": false} + } + ] + } +``` -Port 5432 from EKS Cluster Security Group -Port 5432 from EKS Node Security Group -Port 5432 from EKS Created Security Group +### Install SDP +```bash +helm install sdp stellar/stellar-disbursement-platform -f eks-helm/values.yaml --namespace sdp +``` +### Verify Pods are healthy +``` +kubectl -n sdp get pods +``` -Usage: Applied to RDS instance ## Troubleshooting diff --git a/resources/aws/cloudformation/eks-helm/helm-values.yaml b/resources/aws/cloudformation/eks-helm/helm-values.yaml deleted file mode 100644 index eda190c8f..000000000 --- a/resources/aws/cloudformation/eks-helm/helm-values.yaml +++ /dev/null @@ -1,239 +0,0 @@ -global: - isPubnet: false - ephemeralDatabase: false - eventBroker: - type: "NONE" - urls: "kafka:9092" - consumerGroupId: "group-id" - -sdp: - route: - domain: sdp-backend.mystellarsdpdomain.org - mtnDomain: "*.sdp-backend.mystellarsdpdomain.org" - deployment: - podAnnotations: - prometheus.io/path: /metrics - prometheus.io/port: '{{ include "sdp.metricsPort" . }}' - prometheus.io/scrape: "true" - strategy: - # Ensure we upgrade 1 pod at a time to avoid migration races - rollingUpdate: - maxUnavailable: 1 - maxSurge: 1 - serviceAccount: - create: true - name: sdp-service-account - annotations: - eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} - # =========================== START sdp.kubeSecrets =========================== - kubeSecrets: - secretName: sdp-secrets - create: false - data: - EC256_PRIVATE_KEY: "{{ .Release.Namespace }}/EC256_PRIVATE_KEY" - EC256_PUBLIC_KEY: "{{ .Release.Namespace }}/EC256_PUBLIC_KEY" - SEP10_SIGNING_PRIVATE_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" - SEP10_SIGNING_PUBLIC_KEY: "{{ .Release.Namespace }}/SEP10_SIGNING_PUBLIC_KEY" - DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" - DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" - DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" - CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/channel-encryption-passphrase" - DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" - # =========================== START sdp.configMap =========================== - configMap: - data: - ADMIN_ACCOUNT: "reece@stellar.org" - ENVIRONMENT: "dev" - LOG_LEVEL: "debug" - METRICS_TYPE: "PROMETHEUS" - EMAIL_SENDER_TYPE: "DRY_RUN" - SMS_SENDER_TYPE: "DRY_RUN" - ENABLE_MFA: "false" - NETWORK_PASSPHRASE: "Test SDF Network ; September 2015" - HORIZON_URL: "https://horizon-testnet.stellar.org" - INSTANCE_NAME: "Stellar Disbursement Platform" - CORS_ALLOWED_ORIGINS: "*" - ENABLE_SCHEDULER: "true" - SCHEDULER_RECEIVER_INVITATION_JOB_SECONDS: "10" - SCHEDULER_PAYMENT_JOB_SECONDS: "10" - SDP_UI_BASE_URL: "https://dashboard.mystellarsdpdomain.org" - # =========================== START sdp.ingress =========================== - ingress: - enabled: true - className: "ingress-public" - annotations: - cert-manager.io/cluster-issuer: letsencrypt-prod - tls: - - hosts: - - 'sdp-backend.mystellarsdpdomain.org' - - '*.sdp-backend.mystellarsdpdomain.org' - secretName: sdp-backend-cert -# ============================= anchorPlatform =================================== -anchorPlatform: - route: - domain: ap-sdp-backend.mystellarsdpdomain.org - deployment: - podAnnotations: - prometheus.io/path: /metrics - prometheus.io/port: '{{ include "sdp.ap.metricsPort" . }}' - prometheus.io/scrape: "true" - strategy: - # Ensure we upgrade 1 pod at a time to avoid migration races - type: "RollingUpdate" - rollingUpdate: - maxUnavailable: 1 - maxSurge: 1 - kubeSecrets: - create: false - secretName: sdp-secrets - data: - SECRET_DATA_USERNAME: "{{ .Release.Namespace }}/SECRET_DATA_USERNAME" - SECRET_DATA_PASSWORD: "{{ .Release.Namespace }}/SECRET_DATA_PASSWORD" - DATA_SERVER: "{{ .Release.Namespace }}/DATA_SERVER" - SECRET_SEP10_SIGNING_SEED: "{{ .Release.Namespace }}/SEP10_SIGNING_PRIVATE_KEY" - SECRET_PLATFORM_API_AUTH_SECRET: "{{ .Release.Namespace }}/SECRET_PLATFORM_API_AUTH_SECRET" - SECRET_SEP10_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP10_JWT_SECRET" - SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" - SECRET_SEP24_MORE_INFO_URL_JWT_SECRET: "{{ .Release.Namespace }}/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" - DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" - serviceAccount: - create: true - name: anchor-service-account - annotations: - eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} - configMap: - data: - HOST_URL: https://ap-sdp-backend.mystellarsdpdomain.org - SEP_SERVER_PORT: "8080" - CALLBACK_API_BASE_URL: https://sdp-backend.mystellarsdpdomain.org - CALLBACK_API_AUTH_TYPE: "none" - PLATFORM_SERVER_AUTH_TYPE: "JWT" - APP_LOGGING_LEVEL: "INFO" - DATA_TYPE: "postgres" - DATA_DATABASE: "sdp_dev" - DATA_FLYWAY_ENABLED: "true" - DATA_DDL_AUTO: "update" - METRICS_ENABLED: "false" - METRICS_EXTRAS_ENABLED: "false" - EVENT_BROKER_TYPE: "NONE" - SEP10_ENABLED: "true" - SEP10_WEB_AUTH_DOMAIN: ap-sdp-backend.mystellarsdpdomain.org - SEP10_HOME_DOMAINS: "*.sdp-backend.mystellarsdpdomain.org" - SEP24_ENABLED: "true" - SEP24_INTERACTIVE_URL_BASE_URL: https://sdp-backend.mystellarsdpdomain.org/wallet-registration/start - SEP24_INTERACTIVE_URL_JWT_EXPIRATION: "1800" - SEP24_MORE_INFO_URL_BASE_URL: https://sdp-backend.mystellarsdpdomain.org/wallet-registration/start - SEP1_ENABLED: "true" - SEP1_TOML_TYPE: "url" - SEP1_TOML_VALUE: https://sdp-backend.mystellarsdpdomain.org/.well-known/stellar.toml - ASSETS_TYPE: "json" - ASSETS_VALUE: | - { - "assets": [ - { - "sep24_enabled": true, - "schema": "stellar", - "code": "USDC", - "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - "distribution_account": "GCIA55CO7M7VJNDMQYEJKP4WQRB45CL2RJYPDW64PD2X7VDOZS53A4KK", - "significant_decimals": 7, - "deposit": { - "enabled": true, - "fee_minimum": 0, - "fee_percent": 0, - "min_amount": 1, - "max_amount": 10000 - }, - "withdraw": {"enabled": false} - }, - { - "sep24_enabled": true, - "schema": "stellar", - "code": "XLM", - "distribution_account": "${DISTRIBUTION_PUBLIC_KEY}", - "significant_decimals": 7, - "deposit": { - "enabled": true, - "fee_minimum": 0, - "fee_percent": 0, - "min_amount": 1, - "max_amount": 10000 - }, - "withdraw": {"enabled": false} - } - ] - } - ingress: - enabled: true - className: "ingress-public" - annotations: - cert-manager.io/cluster-issuer: letsencrypt-prod - tls: - - hosts: - - 'ap-sdp-backend.mystellarsdpdomain.org' - secretName: sdp-ap-cert - -# ============================= tss =================================== -tss: - deployment: - podAnnotations: - prometheus.io/path: /metrics - prometheus.io/port: '{{ include "tss.metricsPort" . }}' - prometheus.io/scrape: "true" - strategy: - type: "RollingUpdate" - rollingUpdate: - maxUnavailable: 1 - maxSurge: 1 - kubeSecrets: - create: false - secretName: sdp-secrets - data: - DISTRIBUTION_PUBLIC_KEY: "{{ .Release.Namespace }}/DISTRIBUTION_PUBLIC_KEY" - DISTRIBUTION_SEED: "{{ .Release.Namespace }}/DISTRIBUTION_SEED" - DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" - CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "{{ .Release.Namespace }}/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" - DATABASE_URL: "{{ .Release.Namespace }}/DATABASE_URL" - serviceAccount: - create: true - name: tss-service-account - annotations: - eks.amazonaws.com/role-arn: ${SERVICE_ACCOUNT_ROLE_ARN} - configMap: - data: - LOG_LEVEL: "info" - NETWORK_PASSPHRASE: "Test SDF Network ; September 2015" - HORIZON_URL: "https://horizon-testnet.stellar.org" - NUM_CHANNEL_ACCOUNTS: "3" - MAX_BASE_FEE: "100" - TSS_METRICS_PORT: "9002" - TSS_METRICS_TYPE: "TSS_PROMETHEUS" - EVENT_BROKER_TYPE: "NONE" - BROKER_URLS: "kafka:9092" - CONSUMER_GROUP_ID: "group-id" - KAFKA_SECURITY_PROTOCOL: "PLAINTEXT" -# ============================= dashboard =================================== -dashboard: - enabled: true - route: - domain: "dashboard.mystellarsdpdomain.org" - mtnDomain: "*.dashboard.mystellarsdpdomain.org" - deployment: - strategy: - type: "RollingUpdate" - rollingUpdate: - maxUnavailable: 0 - maxSurge: 1 - configMap: - data: - RECAPTCHA_SITE_KEY: "6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb" - ingress: - enabled: true - className: "ingress-public" - annotations: - cert-manager.io/cluster-issuer: letsencrypt-prod - tls: - - hosts: - - 'dashboard.mystellarsdpdomain.org' - - '*.dashboard.mystellarsdpdomain.org' - secretName: sdp-dashboard-cert diff --git a/resources/aws/cloudformation/eks-helm/values-dev.yaml b/resources/aws/cloudformation/eks-helm/values-dev.yaml index 8fec64d3c..37830c443 100644 --- a/resources/aws/cloudformation/eks-helm/values-dev.yaml +++ b/resources/aws/cloudformation/eks-helm/values-dev.yaml @@ -30,16 +30,16 @@ sdp: secretName: sdp-secrets create: false data: - EC256_PRIVATE_KEY: "/dev/sdp/EC256_PRIVATE_KEY" - EC256_PUBLIC_KEY: "/dev/sdp/EC256_PUBLIC_KEY" - SEP10_SIGNING_PRIVATE_KEY: "/dev/sdp/SEP10_SIGNING_PRIVATE_KEY" - SEP10_SIGNING_PUBLIC_KEY: "/dev/sdp/SEP10_SIGNING_PUBLIC_KEY" - SEP24_JWT_SECRET: "/dev/sdp/SEP24_JWT_SECRET" - DISTRIBUTION_SEED: "/dev/sdp/DISTRIBUTION_SEED" - DISTRIBUTION_PUBLIC_KEY: "/dev/sdp/DISTRIBUTION_PUBLIC_KEY" - DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" - CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/channel-encryption-passphrase" - DATABASE_URL: "/dev/sdp/DATABASE_URL" + EC256_PRIVATE_KEY: "/sdp/dev/EC256_PRIVATE_KEY" + EC256_PUBLIC_KEY: "/sdp/dev/EC256_PUBLIC_KEY" + SEP10_SIGNING_PRIVATE_KEY: "/sdp/dev/SEP10_SIGNING_PRIVATE_KEY" + SEP10_SIGNING_PUBLIC_KEY: "/sdp/dev/SEP10_SIGNING_PUBLIC_KEY" + SEP24_JWT_SECRET: "/sdp/dev/SEP24_JWT_SECRET" + DISTRIBUTION_SEED: "/sdp/dev/DISTRIBUTION_SEED" + DISTRIBUTION_PUBLIC_KEY: "/sdp/dev/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "/sdp/dev/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "/sdp/dev/channel-encryption-passphrase" + DATABASE_URL: "/sdp/dev/DATABASE_URL" RECAPTCHA_SITE_KEY: "/sdp/dev/RECAPTCHA_SITE_KEY" RECAPTCHA_SITE_SECRET_KEY: "/sdp/dev/RECAPTCHA_SITE_SECRET_KEY" # =========================== START sdp.configMap =========================== @@ -90,15 +90,15 @@ anchorPlatform: create: false secretName: sdp-secrets data: - SECRET_DATA_USERNAME: "/dev/sdp/SECRET_DATA_USERNAME" - SECRET_DATA_PASSWORD: "/dev/sdp/SECRET_DATA_PASSWORD" - DATA_SERVER: "/dev/sdp/DATA_SERVER" - SECRET_SEP10_SIGNING_SEED: "/dev/sdp/SEP10_SIGNING_PRIVATE_KEY" - SECRET_PLATFORM_API_AUTH_SECRET: "/dev/sdp/SECRET_PLATFORM_API_AUTH_SECRET" - SECRET_SEP10_JWT_SECRET: "/dev/sdp/SECRET_SEP10_JWT_SECRET" - SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET: "/dev/sdp/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" - SECRET_SEP24_MORE_INFO_URL_JWT_SECRET: "/dev/sdp/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" - DISTRIBUTION_PUBLIC_KEY: "/dev/sdp/DISTRIBUTION_PUBLIC_KEY" + SECRET_DATA_USERNAME: "/sdp/dev/SECRET_DATA_USERNAME" + SECRET_DATA_PASSWORD: "/sdp/dev/SECRET_DATA_PASSWORD" + DATA_SERVER: "/sdp/dev/DATA_SERVER" + SECRET_SEP10_SIGNING_SEED: "/sdp/dev/SEP10_SIGNING_PRIVATE_KEY" + SECRET_PLATFORM_API_AUTH_SECRET: "/sdp/dev/SECRET_PLATFORM_API_AUTH_SECRET" + SECRET_SEP10_JWT_SECRET: "/sdp/dev/SECRET_SEP10_JWT_SECRET" + SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET: "/sdp/dev/SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET" + SECRET_SEP24_MORE_INFO_URL_JWT_SECRET: "/sdp/dev/SECRET_SEP24_MORE_INFO_URL_JWT_SECRET" + DISTRIBUTION_PUBLIC_KEY: "/sdp/dev/DISTRIBUTION_PUBLIC_KEY" serviceAccount: create: true name: anchor-service-account @@ -192,11 +192,11 @@ tss: create: false secretName: sdp-secrets data: - DISTRIBUTION_PUBLIC_KEY: "/dev/sdp/DISTRIBUTION_PUBLIC_KEY" - DISTRIBUTION_SEED: "/dev/sdp/DISTRIBUTION_SEED" - DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" - CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "/dev/sdp/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" - DATABASE_URL: "/dev/sdp/DATABASE_URL" + DISTRIBUTION_PUBLIC_KEY: "/sdp/dev/DISTRIBUTION_PUBLIC_KEY" + DISTRIBUTION_SEED: "/sdp/dev/DISTRIBUTION_SEED" + DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE: "/sdp/dev/DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE" + CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE: "/sdp/dev/CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE" + DATABASE_URL: "/sdp/dev/DATABASE_URL" serviceAccount: create: true name: tss-service-account @@ -227,11 +227,16 @@ dashboard: rollingUpdate: maxUnavailable: 0 maxSurge: 1 - kubeSecrets: - create: false - secretName: sdp-secrets + env: + - name: RECAPTCHA_SITE_KEY + valueFrom: + secretKeyRef: + name: sdp-secrets + key: RECAPTCHA_SITE_KEY + configMap: data: - RECAPTCHA_SITE_KEY: "/sdp/dev/RECAPTCHA_SITE_KEY" + RECAPTCHA_SITE_KEY: 6LcArsEqAAAAAIxEcbaHI4HTp7I5C1RrTv6LC9-Y + API_URL: https://sdp-backend.mystellarsdpdomain.org ingress: enabled: true className: "ingress-public" @@ -241,4 +246,4 @@ dashboard: - hosts: - 'dashboard.mystellarsdpdomain.org' - '*.dashboard.mystellarsdpdomain.org' - secretName: sdp-dashboard-cert + secretName: sdp-dashboard-cert \ No newline at end of file From 82d6251306c30a6e5ee9fb7a2ae29ed4f1d5f4ac Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Tue, 28 Jan 2025 14:05:34 -0800 Subject: [PATCH 07/11] remove ecs for now --- .../cloudformation/eks-helm/values-dev.yaml | 4 +- .../parameters-database-ecs.json | 42 - .../parameters-database-eks.json | 42 - .../aws/cloudformation/parameters-ecs.json | 26 - .../aws/cloudformation/parameters-eks.json | 26 - .../aws/cloudformation/parameters-keys.json | 34 - .../parameters-network-ecs.json | 14 - .../parameters-network-eks.json | 10 - .../aws/cloudformation/sdp-database-ecs.yaml | 285 ---- resources/aws/cloudformation/sdp-ecs.yaml | 1176 ----------------- .../aws/cloudformation/sdp-network-ecs.yaml | 411 ------ 11 files changed, 2 insertions(+), 2068 deletions(-) delete mode 100644 resources/aws/cloudformation/parameters-database-ecs.json delete mode 100644 resources/aws/cloudformation/parameters-database-eks.json delete mode 100644 resources/aws/cloudformation/parameters-ecs.json delete mode 100644 resources/aws/cloudformation/parameters-eks.json delete mode 100644 resources/aws/cloudformation/parameters-keys.json delete mode 100644 resources/aws/cloudformation/parameters-network-ecs.json delete mode 100644 resources/aws/cloudformation/parameters-network-eks.json delete mode 100644 resources/aws/cloudformation/sdp-database-ecs.yaml delete mode 100644 resources/aws/cloudformation/sdp-ecs.yaml delete mode 100644 resources/aws/cloudformation/sdp-network-ecs.yaml diff --git a/resources/aws/cloudformation/eks-helm/values-dev.yaml b/resources/aws/cloudformation/eks-helm/values-dev.yaml index 37830c443..e43259018 100644 --- a/resources/aws/cloudformation/eks-helm/values-dev.yaml +++ b/resources/aws/cloudformation/eks-helm/values-dev.yaml @@ -138,7 +138,7 @@ anchorPlatform: "schema": "stellar", "code": "USDC", "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", + "distribution_account": "NOT_APPLICABLE", "significant_decimals": 7, "deposit": { "enabled": true, @@ -153,7 +153,7 @@ anchorPlatform: "sep24_enabled": true, "schema": "stellar", "code": "native", - "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", + "distribution_account": "NOT_APPLICABLE", "significant_decimals": 7, "deposit": { "enabled": true, diff --git a/resources/aws/cloudformation/parameters-database-ecs.json b/resources/aws/cloudformation/parameters-database-ecs.json deleted file mode 100644 index 3145bc743..000000000 --- a/resources/aws/cloudformation/parameters-database-ecs.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "ParameterKey": "NetworkStackName", - "ParameterValue": "sdp-network-eks" - }, - { - "ParameterKey": "env", - "ParameterValue": "dev" - }, - { - "ParameterKey": "namespace", - "ParameterValue": "sdp" - }, - { - "ParameterKey": "DBInstanceClass", - "ParameterValue": "db.t3.small" - }, - { - "ParameterKey": "DBAllocatedStorage", - "ParameterValue": "20" - }, - { - "ParameterKey": "DBUsername", - "ParameterValue": "postgres" - }, - { - "ParameterKey": "BackupRetentionPeriod", - "ParameterValue": "7" - }, - { - "ParameterKey": "MultiAZ", - "ParameterValue": "false" - }, - { - "ParameterKey": "DeletionProtection", - "ParameterValue": "false" - }, - { - "ParameterKey": "DBPassword", - "ParameterValue": "postgres" - } -] diff --git a/resources/aws/cloudformation/parameters-database-eks.json b/resources/aws/cloudformation/parameters-database-eks.json deleted file mode 100644 index 3145bc743..000000000 --- a/resources/aws/cloudformation/parameters-database-eks.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "ParameterKey": "NetworkStackName", - "ParameterValue": "sdp-network-eks" - }, - { - "ParameterKey": "env", - "ParameterValue": "dev" - }, - { - "ParameterKey": "namespace", - "ParameterValue": "sdp" - }, - { - "ParameterKey": "DBInstanceClass", - "ParameterValue": "db.t3.small" - }, - { - "ParameterKey": "DBAllocatedStorage", - "ParameterValue": "20" - }, - { - "ParameterKey": "DBUsername", - "ParameterValue": "postgres" - }, - { - "ParameterKey": "BackupRetentionPeriod", - "ParameterValue": "7" - }, - { - "ParameterKey": "MultiAZ", - "ParameterValue": "false" - }, - { - "ParameterKey": "DeletionProtection", - "ParameterValue": "false" - }, - { - "ParameterKey": "DBPassword", - "ParameterValue": "postgres" - } -] diff --git a/resources/aws/cloudformation/parameters-ecs.json b/resources/aws/cloudformation/parameters-ecs.json deleted file mode 100644 index c1e27814b..000000000 --- a/resources/aws/cloudformation/parameters-ecs.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "ParameterKey": "FrontendImage", - "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:frontend-3.0.0" - }, - { - "ParameterKey": "BackendImage", - "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:development-amd64" - }, - { - "ParameterKey": "AnchorImage", - "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:anchor-2.6.0" - }, - { - "ParameterKey": "DomainName", - "ParameterValue": "mystellarsdpdomain.org" - }, - { - "ParameterKey": "HostedZoneId", - "ParameterValue": "Z06404593U3HC3DPDLDQK" - }, - { - "ParameterKey": "EmailSenderType", - "ParameterValue": "AWS_EMAIL" - } -] diff --git a/resources/aws/cloudformation/parameters-eks.json b/resources/aws/cloudformation/parameters-eks.json deleted file mode 100644 index c1e27814b..000000000 --- a/resources/aws/cloudformation/parameters-eks.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "ParameterKey": "FrontendImage", - "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:frontend-3.0.0" - }, - { - "ParameterKey": "BackendImage", - "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:development-amd64" - }, - { - "ParameterKey": "AnchorImage", - "ParameterValue": "245943599471.dkr.ecr.us-west-2.amazonaws.com/sdp-dev:anchor-2.6.0" - }, - { - "ParameterKey": "DomainName", - "ParameterValue": "mystellarsdpdomain.org" - }, - { - "ParameterKey": "HostedZoneId", - "ParameterValue": "Z06404593U3HC3DPDLDQK" - }, - { - "ParameterKey": "EmailSenderType", - "ParameterValue": "AWS_EMAIL" - } -] diff --git a/resources/aws/cloudformation/parameters-keys.json b/resources/aws/cloudformation/parameters-keys.json deleted file mode 100644 index 3d4680baa..000000000 --- a/resources/aws/cloudformation/parameters-keys.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "ParameterKey": "EC256PrivateKey", - "ParameterValue": "-----BEGIN EC PRIVATE KEY-----\\nMHcCAQEEIPRRtyc5EQoNPFhkcDzC47B2Zpo5b0NiM3Ftvky86+bEoAoGCCqGSM49\\nAwEHoUQDQgAEWinhVw0QHkZDeZ777zfBKT0cupULkpEd8Y52iPs76AT7JQ1cuGbm\\njxJASNwp907KzNzOZJSV07bFdN/Tkwebgg==\\n-----END EC PRIVATE KEY-----" - }, - { - "ParameterKey": "EC256PublicKey", - "ParameterValue": "-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWinhVw0QHkZDeZ777zfBKT0cupUL\\nkpEd8Y52iPs76AT7JQ1cuGbmjxJASNwp907KzNzOZJSV07bFdN/Tkwebgg==\\n-----END PUBLIC KEY-----" - }, - { - "ParameterKey": "SEP10SigningPrivateKey", - "ParameterValue": "SBTLJ5S6A67SZZPRCIFKXJJO2OMZE5XNKSB7SZYLHWUCQ7XYA5MAOF6M" - }, - { - "ParameterKey": "SEP10SigningPublicKey", - "ParameterValue": "GB3H55YEBHRT7ONUIYYXOXH5JXX4XLXSBIXHWSS2S5AOHPCZBVJH5LYH" - }, - { - "ParameterKey": "DistributionPublicKey", - "ParameterValue": "GCIA55CO7M7VJNDMQYEJKP4WQRB45CL2RJYPDW64PD2X7VDOZS53A4KK" - }, - { - "ParameterKey": "DistributionSeed", - "ParameterValue": "SBOTKS44HJCPKL5VZ5774IZ7ALV4OQEZD4PNCKBVQ522TH6OLNGXSLRI" - }, - { - "ParameterKey": "DistributionAccountEncryptionPassphrase", - "ParameterValue": "SBOTKS44HJCPKL5VZ5774IZ7ALV4OQEZD4PNCKBVQ522TH6OLNGXSLRI" - }, - { - "ParameterKey": "ChannelAccountEncryptionPassphrase", - "ParameterValue": "SBOTKS44HJCPKL5VZ5774IZ7ALV4OQEZD4PNCKBVQ522TH6OLNGXSLRI" - } -] diff --git a/resources/aws/cloudformation/parameters-network-ecs.json b/resources/aws/cloudformation/parameters-network-ecs.json deleted file mode 100644 index 49e711109..000000000 --- a/resources/aws/cloudformation/parameters-network-ecs.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "ParameterKey": "env", - "ParameterValue": "dev" - }, - { - "ParameterKey": "AWSRegion", - "ParameterValue": "us-west-2" - }, - { - "ParameterKey": "CertificateArn", - "ParameterValue": "arn:aws:acm:us-west-2:245943599471:certificate/ff147acc-5267-4d24-9635-cccd00f658b6" - } -] diff --git a/resources/aws/cloudformation/parameters-network-eks.json b/resources/aws/cloudformation/parameters-network-eks.json deleted file mode 100644 index cb63c08c5..000000000 --- a/resources/aws/cloudformation/parameters-network-eks.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "ParameterKey": "env", - "ParameterValue": "prod" - }, - { - "ParameterKey": "AWSRegion", - "ParameterValue": "us-west-2" - } -] diff --git a/resources/aws/cloudformation/sdp-database-ecs.yaml b/resources/aws/cloudformation/sdp-database-ecs.yaml deleted file mode 100644 index 22f5d7a9b..000000000 --- a/resources/aws/cloudformation/sdp-database-ecs.yaml +++ /dev/null @@ -1,285 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Description: RDS Database Stack for SDP - -Parameters: - NetworkStackName: - Type: String - Default: sdp-network - Description: Name of the network stack to import VPC and subnet values from - - env: - Type: String - Default: "dev" - AllowedValues: - - dev - - staging - - prod - Description: Environment name - - namespace: - Type: String - Description: "Kubernetes only. namespace where SDP will be deployed" - Default: "sdp" - - DBInstanceClass: - Type: String - Default: db.t3.small - AllowedValues: - - db.t3.small - - db.t3.medium - - db.t3.large - - db.r5.large - Description: Database instance size - - DBAllocatedStorage: - Type: Number - Default: 20 - MinValue: 20 - MaxValue: 1000 - Description: Size of database storage in GB - - DBUsername: - Type: String - Default: postgres - MinLength: 1 - MaxLength: 16 - AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*" - ConstraintDescription: Must begin with a letter and contain only alphanumeric characters - Description: Database admin username - - BackupRetentionPeriod: - Type: Number - Default: 7 - MinValue: 0 - MaxValue: 35 - Description: Number of days to retain automated backups - - MultiAZ: - Type: String - Default: false - AllowedValues: - - true - - false - Description: Enable Multi-AZ deployment - - DeletionProtection: - Type: String - Default: false - AllowedValues: - - true - - false - Description: Enable deletion protection - - DBPassword: - Type: String - Default: postgres - NoEcho: true - MinLength: 8 - Description: Password for database admin user - -Resources: - RDSSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: Security group for RDS instance - VpcId: - Fn::ImportValue: !Sub ${NetworkStackName}-vpc-id - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 5432 - ToPort: 5432 - SourceSecurityGroupId: - Fn::ImportValue: !Sub ${NetworkStackName}-ecs-services-sg - SecurityGroupEgress: - - IpProtocol: -1 - FromPort: -1 - ToPort: -1 - CidrIp: 0.0.0.0/0 - Tags: - - Key: Name - Value: !Sub ${env}-rds-security-group - - Key: Environment - Value: !Ref env - - DBSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /sdp/${env}/db/credentials - Description: RDS database credentials and connection information - SecretString: !Sub '{"username": "${DBUsername}", "password": "${DBPassword}", "dbname": "sdp_${env}", "port": 5432, "host": "${PostgresInstance.Endpoint.Address}"}' - - DatabaseURLSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /sdp/${env}/db/url - Description: Complete database connection URL - SecretString: !Sub '{"DATABASE_URL": "postgres://${DBUsername}:${DBPassword}@${PostgresInstance.Endpoint.Address}:${PostgresInstance.Endpoint.Port}/sdp_${env}"}' - - DatabaseHostSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /sdp/${env}/db/host - Description: Database host - SecretString: !GetAtt PostgresInstance.Endpoint.Address - - DatabasePortSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /sdp/${env}/db/port - Description: Database port - SecretString: !GetAtt PostgresInstance.Endpoint.Port - - DatabaseNameSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /sdp/${env}/db/name - Description: Database name - SecretString: !Sub sdp_${env} - - SecretDataUsernameSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /${namespace}/SECRET_DATA_USERNAME - Description: Anchor Platform DATA_USER - SecretString: !Ref DBUsername - - SecretDataPasswordSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /${namespace}/SECRET_DATA_PASSWORD - Description: Anchor Platform SECRET_DATA_PASSWORD - SecretString: !Ref DBPassword - - DataServerSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /${namespace}/DATA_SERVER - Description: Anchor Platform DATA_SERVER - SecretString: !GetAtt PostgresInstance.Endpoint.Address - - DatabaseURLSecret: - Type: AWS::SecretsManager::Secret - Properties: - Name: !Sub /${namespace}/DATABASE_URL - Description: Complete database connection URL - SecretString: !Sub "postgres://${DBUsername}:${DBPassword}@${PostgresInstance.Endpoint.Address}:${PostgresInstance.Endpoint.Port}/sdp_${env}" - - DBSubnetGroup: - Type: AWS::RDS::DBSubnetGroup - Properties: - DBSubnetGroupDescription: !Sub ${env}-database-subnet-group - SubnetIds: - - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-1 - - Fn::ImportValue: !Sub ${NetworkStackName}-private-subnet-2 - Tags: - - Key: Name - Value: !Sub ${env}-database-subnet-group - - Key: Environment - Value: !Ref env - - DBParameterGroup: - Type: AWS::RDS::DBParameterGroup - Properties: - Family: postgres14 - Description: Custom parameter group for SDP database - Parameters: - max_connections: "50" - shared_buffers: "4096" - ssl: "1" - Tags: - - Key: Environment - Value: !Ref env - - PostgresInstance: - Type: AWS::RDS::DBInstance - Properties: - DBName: !Sub sdp_${env} - Engine: postgres - EngineVersion: 14 - DBInstanceClass: !Ref DBInstanceClass - AllocatedStorage: !Ref DBAllocatedStorage - StorageType: gp2 - StorageEncrypted: true - MultiAZ: !Ref MultiAZ - PubliclyAccessible: false - DeletionProtection: !Ref DeletionProtection - DBSubnetGroupName: !Ref DBSubnetGroup - VPCSecurityGroups: - - !Ref RDSSecurityGroup - BackupRetentionPeriod: !Ref BackupRetentionPeriod - DBParameterGroupName: !Ref DBParameterGroup - MasterUsername: !Ref DBUsername - MasterUserPassword: !Ref DBPassword - MonitoringInterval: 0 - AutoMinorVersionUpgrade: true - CopyTagsToSnapshot: true - Tags: - - Key: Name - Value: !Sub ${env}-sdp-database - - Key: Environment - Value: !Ref env - - DBEndpointParameter: - Type: AWS::SSM::Parameter - Properties: - Name: !Sub /sdp/${env}/DB_ENDPOINT - Type: String - Value: !GetAtt PostgresInstance.Endpoint.Address - Description: Database endpoint - Tags: - Environment: !Ref env - - DBPortParameter: - Type: AWS::SSM::Parameter - Properties: - Name: !Sub /sdp/${env}/DB_PORT - Type: String - Value: !GetAtt PostgresInstance.Endpoint.Port - Description: Database port - Tags: - Environment: !Ref env - - DBNameParameter: - Type: AWS::SSM::Parameter - Properties: - Name: !Sub /sdp/${env}/DB_NAME - Type: String - Value: !Sub sdp_${env} - Description: Database name - Tags: - Environment: !Ref env - -Outputs: - DatabaseEndpoint: - Description: Database endpoint - Value: !GetAtt PostgresInstance.Endpoint.Address - Export: - Name: !Sub ${AWS::StackName}-db-endpoint - - DatabasePort: - Description: Database port - Value: !GetAtt PostgresInstance.Endpoint.Port - Export: - Name: !Sub ${AWS::StackName}-db-port - - DatabaseName: - Description: Database name - Value: !Sub sdp_${env} - Export: - Name: !Sub ${AWS::StackName}-db-name - - DatabaseSecretArn: - Value: !Ref DBSecret - Export: - Name: !Sub ${AWS::StackName}-db-secret-arn - - DatabaseUrlSecret: - Value: !Ref DatabaseURLSecret - Export: - Name: !Sub ${AWS::StackName}-database-url-secret - - DatabaseSecurityGroup: - Description: Security Group ID for RDS instance - Value: !Ref RDSSecurityGroup - Export: - Name: !Sub ${AWS::StackName}-db-sg \ No newline at end of file diff --git a/resources/aws/cloudformation/sdp-ecs.yaml b/resources/aws/cloudformation/sdp-ecs.yaml deleted file mode 100644 index d35ebb1c3..000000000 --- a/resources/aws/cloudformation/sdp-ecs.yaml +++ /dev/null @@ -1,1176 +0,0 @@ - Parameters: - env: - Type: String - Default: "dev" - - DomainName: - Type: String - - HostedZoneId: - Type: String - - FrontendImage: - Type: String - Default: "stellar/stellar-disbursement-platform-frontend:3.0.0" - - BackendImage: - Type: String - - AnchorImage: - Type: String - Default: "stellar/anchor-platform:2.6.0" - - EmailSenderType: - Type: String - Default: "AWS_EMAIL" - AllowedValues: - - AWS_EMAIL - - TWILLIO_EMAIL - - DRY_RUN - - SmsSenderType: - Type: String - Default: "DRY_RUN" - AllowedValues: - - AWS_SMS - - TWILLIO_SMS - - DRY_RUN - - Resources: - AnchorSepListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-https-listener-arn - Priority: 5 - Conditions: - - Field: host-header - Values: - - !Sub "anchor.${DomainName}" - Actions: - - Type: forward - TargetGroupArn: !Ref AnchorSepTargetGroup - - AnchorPlatformListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-private-https-listener-arn - Priority: 6 - Conditions: - - Field: host-header - Values: - - !Sub "anchor-platform.${DomainName}" - Actions: - - Type: forward - TargetGroupArn: !Ref AnchorPlatformTargetGroup - - TenantListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-private-https-listener-arn - Priority: 8 - Conditions: - - Field: host-header - Values: - - !Sub admin.${DomainName} - - Field: path-pattern - Values: - - "/tenants/*" - Actions: - - Type: forward - TargetGroupArn: !Ref TenantTargetGroup - - SDPListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-https-listener-arn - Priority: 10 - Conditions: - - Field: host-header - Values: - - !Sub "sdp-backend.${DomainName}" - Actions: - - Type: forward - TargetGroupArn: !Ref SDPTargetGroup - - WalletRegistrationRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-https-listener-arn - Priority: 25 - Conditions: - - Field: host-header - Values: - - !Sub sdp-backend.${DomainName} - - Field: path-pattern - Values: - - "/wallet-registration/*" - Actions: - - Type: forward - TargetGroupArn: !Ref SDPTargetGroup - - TomlRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-https-listener-arn - Priority: 26 - Conditions: - - Field: host-header - Values: - - !Sub "*.${DomainName}" - - Field: path-pattern - Values: - - "/.well-known/*" - Actions: - - Type: forward - TargetGroupArn: !Ref SDPTargetGroup - - SepListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-https-listener-arn - Priority: 29 - Conditions: - - Field: host-header - Values: - - !Sub "*.${DomainName}" - - Field: path-pattern - Values: - - "/sep24/*" - Actions: - - Type: forward - TargetGroupArn: !Ref AnchorSepTargetGroup - - FrontendListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: - Fn::ImportValue: sdp-network-https-listener-arn - Priority: 40 - Conditions: - - Field: host-header - Values: - - !Sub "*.${DomainName}" - Actions: - - Type: forward - TargetGroupArn: !Ref FrontendTargetGroup - - SDPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: - Fn::ImportValue: sdp-network-vpc-id - Port: 8000 - Protocol: HTTP - TargetType: ip - HealthCheckPath: /health - HealthCheckEnabled: true - HealthCheckIntervalSeconds: 30 - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - UnhealthyThresholdCount: 5 - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-sdp-tg - - TenantTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: - Fn::ImportValue: sdp-network-vpc-id - Port: 8003 - Protocol: HTTP - TargetType: ip - HealthCheckPath: /health - HealthCheckEnabled: true - HealthCheckIntervalSeconds: 30 - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - UnhealthyThresholdCount: 5 - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-tenant-tg - - AnchorPlatformTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: - Fn::ImportValue: sdp-network-vpc-id - Port: 8085 - Protocol: HTTP - TargetType: ip - HealthCheckPath: /health?checks=config - HealthCheckEnabled: true - HealthCheckIntervalSeconds: 60 - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - UnhealthyThresholdCount: 5 - HealthCheckPort: 8080 - TargetGroupAttributes: - - Key: deregistration_delay.timeout_seconds - Value: '30' - - Key: slow_start.duration_seconds - Value: '60' - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-anchor-platform-tg - - AnchorSepTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: - Fn::ImportValue: sdp-network-vpc-id - Port: 8080 - Protocol: HTTP - TargetType: ip - HealthCheckPath: /health?checks=config - HealthCheckEnabled: true - HealthCheckIntervalSeconds: 60 - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - UnhealthyThresholdCount: 5 - HealthCheckPort: 8080 - TargetGroupAttributes: - - Key: deregistration_delay.timeout_seconds - Value: '30' - - Key: slow_start.duration_seconds - Value: '60' - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-anchor-sep-tg - - FrontendTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: - Fn::ImportValue: sdp-network-vpc-id - Port: 80 - Protocol: HTTP - TargetType: ip - HealthCheckEnabled: true - HealthCheckPath: / - HealthCheckIntervalSeconds: 30 - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - UnhealthyThresholdCount: 5 - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-frontend-tg - - ECSCluster: - Type: AWS::ECS::Cluster - Properties: - ClusterName: !Sub ${env}-${AWS::StackName}-cluster - CapacityProviders: - - FARGATE - DefaultCapacityProviderStrategy: - - CapacityProvider: FARGATE - Weight: 1 - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-cluster - - ECSTaskExecutionRolePolicy: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Sub ${env}-${AWS::StackName}-task-execution-role-policy - Roles: [!Ref ECSTaskExecutionRole] - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - "secretsmanager:GetSecretValue" - Resource: "*" - - Effect: Allow - Action: - - "ssm:GetParameters" - - "ssm:GetParameter" - - "ssm:GetParametersByPath" - Resource: - - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sdp/*" - - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sdp/${env}/*" - - Effect: Allow - Action: - - "logs:CreateLogGroup" - - "logs:CreateLogStream" - - "logs:PutLogEvents" - Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${env}-${AWS::StackName}*" - - Effect: Allow - Action: - - "ecr:GetAuthorizationToken" - - "ecr:BatchCheckLayerAvailability" - - "ecr:GetDownloadUrlForLayer" - - "ecr:BatchGetImage" - Resource: !Sub "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/sdp-dev" - - Effect: Allow - Action: - - "ecr:GetAuthorizationToken" - Resource: "*" - - Effect: Allow - Action: - - "logs:CreateLogGroup" - - "logs:CreateLogStream" - - "logs:PutLogEvents" - Resource: - - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${env}-${AWS::StackName}/tss:*" - - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${env}-${AWS::StackName}/sdp:*" - - ECSTaskExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: ecs-tasks.amazonaws.com - Action: sts:AssumeRole - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy - - arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess - - ECSTaskRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: ecs-tasks.amazonaws.com - Action: sts:AssumeRole - ManagedPolicyArns: - - arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess - Policies: - - PolicyName: SESSendEmailPolicy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - ses:SendEmail - - ses:SendRawEmail - Resource: '*' - - FrontendTaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: !Sub ${env}-${AWS::StackName}-frontend - Cpu: 1024 - Memory: 3072 - NetworkMode: awsvpc - RequiresCompatibilities: - - FARGATE - ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn - TaskRoleArn: !GetAtt ECSTaskRole.Arn - ContainerDefinitions: - - Name: frontend - Image: !Ref FrontendImage - Essential: true - PortMappings: - - ContainerPort: 80 - Protocol: tcp - Environment: - - Name: API_URL - Value: !Sub https://sdp-backend.${DomainName} - - Name: STELLAR_EXPERT_URL - Value: https://stellar.expert/explorer/testnet - - Name: HORIZON_URL - Value: https://horizon-testnet.stellar.org - - Name: USDC_ASSET_ISSUER - Value: GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5 - - Name: RECAPTCHA_SITE_KEY - Value: RECAPTCHA_SITE_KEY_VALUE - - Name: SINGLE_TENANT_MODE - Value: "false" - - Name: PUBLIC_ALB_DNS - Value: - Fn::ImportValue: sdp-network-public-alb-dns - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-create-group: 'true' - awslogs-group: !Sub /ecs/${env}-${AWS::StackName} - awslogs-region: !Ref AWS::Region - awslogs-stream-prefix: frontend - EntryPoint: - - /bin/sh - - -c - Command: - - | - cat /usr/share/nginx/html/index.html && \ - mkdir -p /usr/share/nginx/html/settings && \ - echo "window._env_ = { - API_URL: \"$API_URL\", - RECAPTCHA_SITE_KEY: \"$RECAPTCHA_SITE_KEY\", - HORIZON_URL: \"$HORIZON_URL\", - STELLAR_EXPERT_URL: \"$STELLAR_EXPERT_URL\", - SINGLE_TENANT_MODE: $SINGLE_TENANT_MODE - };" > /usr/share/nginx/html/settings/env-config.js && - exec nginx -g 'daemon off;' - - TSSTaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: !Sub ${env}-${AWS::StackName}-tss - Cpu: 1024 - Memory: 3072 - NetworkMode: awsvpc - RequiresCompatibilities: - - FARGATE - ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn - TaskRoleArn: !GetAtt ECSTaskRole.Arn - ContainerDefinitions: - - Name: tss - Image: !Ref BackendImage - Essential: true - PortMappings: - - ContainerPort: 9000 - Protocol: tcp - - ContainerPort: 9002 - Protocol: tcp - EntryPoint: - - /bin/bash - - -c - Command: - - | - set -e - echo "Starting TSS initialization..." - - # Wait for database to be ready - sleep 10 - - echo "Verifying and managing channel accounts..." - # First verify and cleanup invalid accounts - ./stellar-disbursement-platform channel-accounts verify --delete-invalid-accounts - - # Ensure we have the required number of channel accounts - ./stellar-disbursement-platform channel-accounts ensure 3 - - echo "Starting TSS server..." - # Start the TSS server - exec ./stellar-disbursement-platform tss - Environment: - - Name: LOG_LEVEL - Value: info - - Name: NETWORK_PASSPHRASE - Value: "Test SDF Network ; September 2015" - - Name: HORIZON_URL - Value: "https://horizon-testnet.stellar.org" - - Name: NUM_CHANNEL_ACCOUNTS - Value: "3" - - Name: MAX_BASE_FEE - Value: "100" - - Name: TSS_METRICS_PORT - Value: "9002" - - Name: TSS_METRICS_TYPE - Value: "TSS_PROMETHEUS" - - Name: EVENT_BROKER_TYPE - Value: "NONE" - - Name: BROKER_URLS - Value: "kafka:9092" - - Name: CONSUMER_GROUP_ID - Value: "group-id" - - Name: KAFKA_SECURITY_PROTOCOL - Value: "PLAINTEXT" - HealthCheck: - Command: - - CMD-SHELL - - curl -f http://localhost:9002/metrics || exit 1 - Interval: 30 - Timeout: 5 - Retries: 3 - StartPeriod: 60 - Secrets: - - Name: DISTRIBUTION_PUBLIC_KEY - ValueFrom: !Sub - - "${secret}:public_key::" - - secret: !ImportValue sdp-keys-distribution-secret-arn - - Name: DISTRIBUTION_SEED - ValueFrom: !Sub - - "${secret}:seed::" - - secret: !ImportValue sdp-keys-distribution-secret-arn - - Name: DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE - ValueFrom: !Sub - - "${secret}:encryption_passphrase::" - - secret: !ImportValue sdp-keys-distribution-secret-arn - - Name: CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE - ValueFrom: !Sub - - "${secret}:encryption_passphrase::" - - secret: !ImportValue sdp-keys-channel-secret-arn - - Name: DATABASE_URL - ValueFrom: !Sub - - "${secret}:DATABASE_URL::" - - secret: !ImportValue sdp-database-database-url-secret - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-create-group: 'true' - awslogs-group: !Sub /ecs/${env}-${AWS::StackName}/tss - awslogs-region: !Ref AWS::Region - awslogs-stream-prefix: tss - awslogs-multiline-pattern: '^\d{4}-\d{2}-\d{2}' - awslogs-datetime-format: '%Y-%m-%d %H:%M:%S' - LinuxParameters: - InitProcessEnabled: true - - SDPTaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: !Sub ${env}-${AWS::StackName}-sdp - Cpu: 1024 - Memory: 3072 - NetworkMode: awsvpc - RequiresCompatibilities: - - FARGATE - ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn - TaskRoleArn: !GetAtt ECSTaskRole.Arn - ContainerDefinitions: - - Name: sdp - Image: !Ref BackendImage - Essential: true - PortMappings: - - ContainerPort: 8000 - Protocol: tcp - - ContainerPort: 8002 - Protocol: tcp - - ContainerPort: 8003 - Protocol: tcp - - ContainerPort: 2345 - Protocol: tcp - EntryPoint: - - /bin/bash - - -c - Command: - - | - ./stellar-disbursement-platform db admin migrate up && \ - ./stellar-disbursement-platform db tss migrate up && \ - ./stellar-disbursement-platform db auth migrate up --all && \ - ./stellar-disbursement-platform db sdp migrate up --all && \ - /go/bin/dlv exec --continue --accept-multiclient --headless --listen=:2345 --api-version=2 --log ./stellar-disbursement-platform -- serve - LinuxParameters: - Capabilities: - Add: - - SYS_PTRACE - Environment: - - Name: AWS_REGION - Value: !Ref AWS::Region - - Name: BASE_URL - Value: !Sub https://sdp-backend.${DomainName} - - Name: SDP_UI_BASE_URL - Value: !Sub https://sdp-frontend.${DomainName} - - Name: DISABLE_RECAPTCHA - Value: 'true' - - Name: ENVIRONMENT - Value: !Ref env - - Name: SMS_SENDER_TYPE - Value: !Ref SmsSenderType - - Name: ENABLE_MFA - Value: 'false' - - Name: NETWORK_PASSPHRASE - Value: Test SDF Network ; September 2015 - - Name: LOG_LEVEL - Value: debug - - Name: HORIZON_URL - Value: https://horizon-testnet.stellar.org - - Name: INSTANCE_NAME - Value: "Stellar Disbursement Platform" - - Name: CORS_ALLOWED_ORIGINS - Value: "*" - - Name: SEP24_JWT_SECRET - Value: "jwt_secret_1234567890" - - Name: ANCHOR_PLATFORM_BASE_PLATFORM_URL - Value: !Sub https://anchor-platform.${DomainName} - - Name: ANCHOR_PLATFORM_BASE_SEP_URL - Value: !Sub https://anchor.${DomainName} - - Name: ANCHOR_PLATFORM_OUTGOING_JWT_SECRET - Value: "mySdpToAnchorPlatformSecret" - - Name: RECAPTCHA_SITE_KEY - Value: "6Lcw864qAAAAAMRkQZwXdOIMy-EYlqXPkOPf_Jzb" - - Name: ADMIN_ACCOUNT - Value: admin - - Name: ADMIN_API_KEY - Value: api_key_1234567890 - - Name: AWS_REGION - Value: !Ref AWS::Region - - Name: EVENT_BROKER_TYPE - Value: "NONE" - - Name: BROKER_URLS - Value: "kafka:9092" - - Name: CONSUMER_GROUP_ID - Value: "group-id" - - Name: KAFKA_SECURITY_PROTOCOL - Value: "PLAINTEXT" - - Name: ENABLE_SCHEDULER - Value: "true" - - Name: SCHEDULER_RECEIVER_INVITATION_JOB_SECONDS - Value: "10" - - Name: SCHEDULER_PAYMENT_JOB_SECONDS - Value: "10" - - Name: METRICS_PORT - Value: "8002" - - Name: METRICS_TYPE - Value: "PROMETHEUS" - - Name: EMAIL_SENDER_TYPE - Value: !Ref EmailSenderType - - Name: AWS_SES_SENDER_ID - Value: !Sub "noreply@${DomainName}" - Secrets: - - Name: EC256_PRIVATE_KEY - ValueFrom: !Sub - - "${secret}:private_key::" - - secret: !ImportValue sdp-keys-ec256-secret-arn - - Name: EC256_PUBLIC_KEY - ValueFrom: !Sub - - "${secret}:public_key::" - - secret: !ImportValue sdp-keys-ec256-secret-arn - - Name: SEP10_SIGNING_PRIVATE_KEY - ValueFrom: !Sub - - "${secret}:signing_private_key::" - - secret: !ImportValue sdp-keys-sep10-secret-arn - - Name: SEP10_SIGNING_PUBLIC_KEY - ValueFrom: !Sub - - "${secret}:signing_public_key::" - - secret: !ImportValue sdp-keys-sep10-secret-arn - - Name: DISTRIBUTION_SEED - ValueFrom: !Sub - - "${secret}:seed::" - - secret: !ImportValue sdp-keys-distribution-secret-arn - - Name: DISTRIBUTION_PUBLIC_KEY - ValueFrom: !Sub - - "${secret}:public_key::" - - secret: !ImportValue sdp-keys-distribution-secret-arn - - Name: DISTRIBUTION_ACCOUNT_ENCRYPTION_PASSPHRASE - ValueFrom: !Sub - - "${secret}:encryption_passphrase::" - - secret: !ImportValue sdp-keys-distribution-secret-arn - - Name: CHANNEL_ACCOUNT_ENCRYPTION_PASSPHRASE - ValueFrom: !Sub - - "${secret}:encryption_passphrase::" - - secret: !ImportValue sdp-keys-channel-secret-arn - - Name: DATABASE_URL - ValueFrom: !Sub - - "${secret}:DATABASE_URL::" - - secret: !ImportValue sdp-database-database-url-secret - - Name: RECAPTCHA_SITE_SECRET_KEY - ValueFrom: !Ref RecaptchaSiteSecretKeyParam - - Name: AWS_ACCESS_KEY_ID - ValueFrom: !Ref AWSSESAccessKeyParam - - Name: AWS_SECRET_ACCESS_KEY - ValueFrom: !Ref AWSSESSecretKeyParam - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-create-group: 'true' - awslogs-group: !Sub /ecs/${env}-${AWS::StackName}/backend - awslogs-region: !Ref AWS::Region - awslogs-stream-prefix: sdp - awslogs-multiline-pattern: '^\d{4}-\d{2}-\d{2}' - awslogs-datetime-format: '%Y-%m-%d %H:%M:%S' - - AnchorTaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: !Sub ${env}-${AWS::StackName}-anchor - Cpu: 1024 - Memory: 3072 - NetworkMode: awsvpc - RequiresCompatibilities: - - FARGATE - ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn - TaskRoleArn: !GetAtt ECSTaskRole.Arn - ContainerDefinitions: - - Name: anchorplatform - Image: !Ref AnchorImage - Essential: true - PortMappings: - - ContainerPort: 8080 - Protocol: tcp - Name: sep-server - AppProtocol: http - - ContainerPort: 8085 - Protocol: tcp - Name: platform-server - AppProtocol: http - - ContainerPort: 8082 - Protocol: tcp - Name: metrics - AppProtocol: http - Command: - - "--sep-server" - - "--platform-server" - - "--platform" - - "linux/amd64" - Environment: - - Name: HOST_URL - Value: !Sub https://anchor.${DomainName} - - Name: SEP_SERVER_PORT - Value: "8080" - - Name: CALLBACK_API_BASE_URL - Value: !Sub https://sdp-backend.${DomainName} - - Name: CALLBACK_API_AUTH_TYPE - Value: "none" - - Name: PLATFORM_SERVER_AUTH_TYPE - Value: "JWT" - - Name: APP_LOGGING_LEVEL - Value: "INFO" - - Name: DATA_TYPE - Value: "postgres" - - Name: DATA_DATABASE - Value: "postgres" - - Name: DATA_FLYWAY_ENABLED - Value: "true" - - Name: DATA_DDL_AUTO - Value: "update" - - Name: METRICS_ENABLED - Value: "false" - - Name: METRICS_EXTRAS_ENABLED - Value: "false" - - Name: EVENT_BROKER_TYPE - Value: "NONE" - - Name: SEP10_ENABLED - Value: "true" - - Name: SEP10_WEB_AUTH_DOMAIN - Value: !Sub anchor.${DomainName} - - Name: SEP10_HOME_DOMAINS - Value: !Sub "*.${DomainName}" - - Name: SEP24_ENABLED - Value: "true" - - Name: SEP24_INTERACTIVE_URL_BASE_URL - Value: !Sub https://sdp-backend.${DomainName}/wallet-registration/start - - Name: SEP24_INTERACTIVE_URL_JWT_EXPIRATION - Value: "1800" - - Name: SEP24_MORE_INFO_URL_BASE_URL - Value: !Sub https://sdp-backend.${DomainName}/wallet-registration/start - - Name: SEP1_ENABLED - Value: "true" - - Name: SEP1_TOML_TYPE - Value: "url" - - Name: SEP1_TOML_VALUE - Value: !Sub https://sdp-backend.${DomainName}/.well-known/stellar.toml - - Name: SECRET_PLATFORM_API_AUTH_SECRET - Value: "mySdpToAnchorPlatformSecret" - - Name: SECRET_SEP10_JWT_SECRET - Value: "jwt_secret_1234567890" - - Name: SECRET_SEP24_INTERACTIVE_URL_JWT_SECRET - Value: "jwt_secret_1234567890" - - Name: SECRET_SEP24_MORE_INFO_URL_JWT_SECRET - Value: "jwt_secret_1234567890" - - Name: ASSETS_TYPE - Value: "json" - - Name: ASSETS_VALUE - Value: !Sub - - | - { - "assets": [ - { - "sep24_enabled": true, - "schema": "stellar", - "code": "USDC", - "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - "distribution_account": "${distributionAccount}", - "significant_decimals": 7, - "deposit": { - "enabled": true, - "fee_minimum": 0, - "fee_percent": 0, - "min_amount": 1, - "max_amount": 10000 - }, - "withdraw": {"enabled": false} - }, - { - "sep24_enabled": true, - "schema": "stellar", - "code": "native", - "issuer": "", - "distribution_account": "${distributionAccount}", - "significant_decimals": 7, - "deposit": { - "enabled": true, - "fee_minimum": 0, - "fee_percent": 0, - "min_amount": 1, - "max_amount": 10000 - }, - "withdraw": {"enabled": false} - } - ] - } - - distributionAccount: !Sub - - "{{resolve:secretsmanager:${SecretArn}:SecretString:public_key}}" - - SecretArn: !ImportValue sdp-keys-distribution-secret-arn - Secrets: - - Name: SECRET_DATA_USERNAME - ValueFrom: !Sub - - "${secret}:username::" - - secret: !ImportValue sdp-database-db-secret - - Name: SECRET_DATA_PASSWORD - ValueFrom: !Sub - - "${secret}:password::" - - secret: !ImportValue sdp-database-db-secret - - Name: DATA_SERVER - ValueFrom: !Sub - - "${secret}:host::" - - secret: !ImportValue sdp-database-db-secret - - Name: SECRET_SEP10_SIGNING_SEED - ValueFrom: !Sub - - "${secret}:signing_private_key::" - - secret: !ImportValue sdp-keys-sep10-secret-arn - - Name: DISTRIBUTION_PUBLIC_KEY - ValueFrom: !Sub - - "${secret}:public_key::" - - secret: !ImportValue sdp-keys-distribution-secret-arn - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-create-group: 'true' - awslogs-group: !Sub /ecs/${env}-${AWS::StackName} - awslogs-region: !Ref AWS::Region - awslogs-stream-prefix: anchor - - TSSLogGroup: - Type: AWS::Logs::LogGroup - Properties: - LogGroupName: !Sub /ecs/${env}-${AWS::StackName}/tss - RetentionInDays: 1 - - SDPLogGroup: - Type: AWS::Logs::LogGroup - Properties: - LogGroupName: !Sub /ecs/${env}-${AWS::StackName}/sdp - RetentionInDays: 1 - - FrontendService: - Type: AWS::ECS::Service - DependsOn: - - FrontendListenerRule - - SDPService - Properties: - ServiceName: !Sub ${env}-${AWS::StackName}-frontend - Cluster: !Ref ECSCluster - TaskDefinition: !Ref FrontendTaskDefinition - DesiredCount: 1 - LaunchType: FARGATE - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: DISABLED - SecurityGroups: - - Fn::ImportValue: sdp-network-ecs-services-sg - Subnets: - - Fn::ImportValue: sdp-network-private-subnet-1 - - Fn::ImportValue: sdp-network-private-subnet-2 - LoadBalancers: - - ContainerName: frontend - ContainerPort: 80 - TargetGroupArn: !Ref FrontendTargetGroup - HealthCheckGracePeriodSeconds: 300 - - TSSService: - Type: AWS::ECS::Service - DependsOn: - - SDPService - Properties: - DeploymentConfiguration: - DeploymentCircuitBreaker: - Enable: false - Rollback: false - MaximumPercent: 100 - MinimumHealthyPercent: 0 - ServiceName: !Sub ${env}-${AWS::StackName}-tss - Cluster: !Ref ECSCluster - TaskDefinition: !Ref TSSTaskDefinition - DesiredCount: 1 - LaunchType: FARGATE - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: DISABLED - SecurityGroups: - - Fn::ImportValue: sdp-network-ecs-services-sg # Updated to use the single ECS services security group - Subnets: - - Fn::ImportValue: sdp-network-private-subnet-1 - - Fn::ImportValue: sdp-network-private-subnet-2 - - SDPService: - Type: AWS::ECS::Service - DependsOn: - - SDPListenerRule - - SDPListenerRule - - TenantListenerRule - - SDPTargetGroup - - TenantTargetGroup - - SDPTaskDefinition - - SDPLogGroup - Properties: - ServiceName: !Sub ${env}-${AWS::StackName}-sdp - Cluster: !Ref ECSCluster - TaskDefinition: !Ref SDPTaskDefinition - DesiredCount: 1 - LaunchType: FARGATE - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: DISABLED - SecurityGroups: - - Fn::ImportValue: sdp-network-ecs-services-sg - Subnets: - - Fn::ImportValue: sdp-network-private-subnet-1 - - Fn::ImportValue: sdp-network-private-subnet-2 - LoadBalancers: - - ContainerName: sdp - ContainerPort: 8000 - TargetGroupArn: !Ref SDPTargetGroup - - ContainerName: sdp - ContainerPort: 8003 - TargetGroupArn: !Ref TenantTargetGroup - HealthCheckGracePeriodSeconds: 300 - DeploymentConfiguration: - DeploymentCircuitBreaker: - Enable: true - Rollback: true - - AnchorService: - Type: AWS::ECS::Service - DependsOn: - - AnchorSepListenerRule - - SDPService - Properties: - ServiceName: !Sub ${env}-${AWS::StackName}-anchor - Cluster: !Ref ECSCluster - TaskDefinition: !Ref AnchorTaskDefinition - DesiredCount: 1 - LaunchType: FARGATE - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: DISABLED - SecurityGroups: - - Fn::ImportValue: sdp-network-ecs-services-sg - Subnets: - - Fn::ImportValue: sdp-network-private-subnet-1 - - Fn::ImportValue: sdp-network-private-subnet-2 - LoadBalancers: - - ContainerName: anchorplatform - ContainerPort: 8080 - TargetGroupArn: !Ref AnchorSepTargetGroup - - ContainerName: anchorplatform - ContainerPort: 8085 - TargetGroupArn: !Ref AnchorPlatformTargetGroup - HealthCheckGracePeriodSeconds: 300 - - BaseDomainRecord: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneName: !Sub ${DomainName}. - Name: !Ref DomainName - Type: A - AliasTarget: - DNSName: - Fn::ImportValue: sdp-network-public-alb-dns - HostedZoneId: - Fn::ImportValue: sdp-network-public-alb-hosted-zone - EvaluateTargetHealth: true - - FrontendDNSRecord: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneName: !Sub ${DomainName}. - Name: !Sub sdp-frontend.${DomainName}. - Type: A - AliasTarget: - DNSName: - Fn::ImportValue: sdp-network-public-alb-dns - HostedZoneId: - Fn::ImportValue: sdp-network-public-alb-hosted-zone - EvaluateTargetHealth: true - - BackendDNSRecord: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneName: !Sub ${DomainName}. - Name: !Sub sdp-backend.${DomainName}. - Type: A - AliasTarget: - DNSName: - Fn::ImportValue: sdp-network-public-alb-dns - HostedZoneId: - Fn::ImportValue: sdp-network-public-alb-hosted-zone - EvaluateTargetHealth: true - - AnchorDNSRecord: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneName: !Sub ${DomainName}. - Name: !Sub anchor.${DomainName}. - Type: A - AliasTarget: - DNSName: - Fn::ImportValue: sdp-network-public-alb-dns - HostedZoneId: - Fn::ImportValue: sdp-network-public-alb-hosted-zone - EvaluateTargetHealth: true - - AnchorPlatformPrivateDNSRecord: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneName: !Sub ${DomainName}. - Name: !Sub anchor-platform.${DomainName}. - Type: A - AliasTarget: - DNSName: - Fn::ImportValue: sdp-network-private-alb-dns - HostedZoneId: - Fn::ImportValue: sdp-network-private-alb-hosted-zone - EvaluateTargetHealth: true - - AdminDNSRecord: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneName: !Sub ${DomainName}. - Name: !Sub admin.${DomainName}. - Type: A - AliasTarget: - DNSName: - Fn::ImportValue: sdp-network-private-alb-dns - HostedZoneId: - Fn::ImportValue: sdp-network-private-alb-hosted-zone - EvaluateTargetHealth: true - - WildcardDNSRecord: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneName: !Sub ${DomainName}. - Name: !Sub "*.${DomainName}." - Type: A - AliasTarget: - DNSName: - Fn::ImportValue: sdp-network-public-alb-dns - HostedZoneId: - Fn::ImportValue: sdp-network-public-alb-hosted-zone - EvaluateTargetHealth: true - - RecaptchaSiteSecretKeyParam: - Type: AWS::SSM::Parameter - Properties: - Name: !Sub "/sdp/${env}/RECAPTCHA_SITE_SECRET_KEY" - Type: String - Value: "RECAPTCHA_SITE_KEY_VALUE" - Tags: - env: !Ref env - - AWSSESAccessKeyParam: - Type: AWS::SSM::Parameter - Properties: - Name: !Sub "/sdp/${env}/AWS_ACCESS_KEY_ID" - Type: String - Value: !Ref SESUserAccessKey - Tags: - env: !Ref env - - AWSSESSecretKeyParam: - Type: AWS::SSM::Parameter - Properties: - Name: !Sub "/sdp/${env}/AWS_SECRET_ACCESS_KEY" - Type: String - Value: !GetAtt SESUserAccessKey.SecretAccessKey - Tags: - env: !Ref env - - AWSSESSenderIDParam: - Type: AWS::SSM::Parameter - Properties: - Name: !Sub "/sdp/${env}/AWS_SES_SENDER_ID" - Type: String - Value: !Sub "noreply@${DomainName}" - Tags: - env: !Ref env - - EmailDomainIdentity: - Type: AWS::SES::EmailIdentity - Properties: - EmailIdentity: !Ref DomainName - DkimAttributes: - SigningEnabled: true - ConfigurationSetAttributes: - ConfigurationSetName: !Ref EmailConfigurationSet - - DkimRecord1: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneId: !Ref HostedZoneId - Name: !GetAtt EmailDomainIdentity.DkimDNSTokenName1 - Type: CNAME - TTL: 300 - ResourceRecords: - - !GetAtt EmailDomainIdentity.DkimDNSTokenValue1 - - DkimRecord2: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneId: !Ref HostedZoneId - Name: !GetAtt EmailDomainIdentity.DkimDNSTokenName2 - Type: CNAME - TTL: 300 - ResourceRecords: - - !GetAtt EmailDomainIdentity.DkimDNSTokenValue2 - - DkimRecord3: - Type: AWS::Route53::RecordSet - Properties: - HostedZoneId: !Ref HostedZoneId - Name: !GetAtt EmailDomainIdentity.DkimDNSTokenName3 - Type: CNAME - TTL: 300 - ResourceRecords: - - !GetAtt EmailDomainIdentity.DkimDNSTokenValue3 - - EmailConfigurationSet: - Type: AWS::SES::ConfigurationSet - Properties: - Name: !Sub "${env}-${AWS::StackName}-config-set" - DeliveryOptions: - TlsPolicy: REQUIRE - ReputationOptions: - ReputationMetricsEnabled: true - SendingOptions: - SendingEnabled: true - SuppressionOptions: - SuppressedReasons: - - BOUNCE - - COMPLAINT - - SESUser: - Type: AWS::IAM::User - Properties: - UserName: !Sub "${env}-${AWS::StackName}-ses-smtp" - Policies: - - PolicyName: SESSendEmail - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - ses:SendRawEmail - - ses:SendEmail - Resource: "*" - - SESUserAccessKey: - Type: AWS::IAM::AccessKey - Properties: - UserName: !Ref SESUser - - Outputs: - FrontendURL: - Value: !Sub https://sdp-frontend.${DomainName} - Export: - Name: !Sub ${AWS::StackName}-sdp-frontend-url - - DomainName: - Value: !Ref DomainName - Export: - Name: !Sub ${AWS::StackName}-domain-name diff --git a/resources/aws/cloudformation/sdp-network-ecs.yaml b/resources/aws/cloudformation/sdp-network-ecs.yaml deleted file mode 100644 index 425d92350..000000000 --- a/resources/aws/cloudformation/sdp-network-ecs.yaml +++ /dev/null @@ -1,411 +0,0 @@ -Parameters: - AWSRegion: - Type: String - Default: "us-west-1" - - env: - Type: String - Default: "dev" - AllowedValues: - - dev - - staging - - prod - - VPCCidr: - Type: String - Default: "10.0.0.0/16" - - PublicSubnet1CIDR: - Type: String - Default: "10.0.0.0/24" - - PublicSubnet2CIDR: - Type: String - Default: "10.0.1.0/24" - - PrivateSubnet1CIDR: - Type: String - Default: "10.0.2.0/24" - - PrivateSubnet2CIDR: - Type: String - Default: "10.0.3.0/24" - - CertificateArn: - Type: String - default: "" - -Resources: - SDPVPC: - Type: AWS::EC2::VPC - Properties: - CidrBlock: !Ref VPCCidr - EnableDnsHostnames: true - EnableDnsSupport: true - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-vpc - - Key: env - Value: !Ref env - - InternetGateway: - Type: AWS::EC2::InternetGateway - Properties: - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-igw - - Key: env - Value: !Ref env - - AttachGateway: - Type: AWS::EC2::VPCGatewayAttachment - Properties: - VpcId: !Ref SDPVPC - InternetGatewayId: !Ref InternetGateway - - NatGatewayEIP: - Type: AWS::EC2::EIP - DependsOn: AttachGateway - Properties: - Domain: vpc - Tags: - - Key: env - Value: !Ref env - - # Public Subnets - Only for ALB - PublicSubnet1: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref SDPVPC - CidrBlock: !Ref PublicSubnet1CIDR - AvailabilityZone: !Select [0, !GetAZs ''] - MapPublicIpOnLaunch: true - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-public-1 - - Key: env - Value: !Ref env - - Key: Tier - Value: Public - - PublicSubnet2: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref SDPVPC - CidrBlock: !Ref PublicSubnet2CIDR - AvailabilityZone: !Select [1, !GetAZs ''] - MapPublicIpOnLaunch: true - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-public-2 - - Key: env - Value: !Ref env - - Key: Tier - Value: Public - - # Private Subnets - For ECS Services and RDS - PrivateSubnet1: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref SDPVPC - CidrBlock: !Ref PrivateSubnet1CIDR - AvailabilityZone: !Select [0, !GetAZs ''] - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-private-1 - - Key: env - Value: !Ref env - - Key: Tier - Value: Private - - PrivateSubnet2: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref SDPVPC - CidrBlock: !Ref PrivateSubnet2CIDR - AvailabilityZone: !Select [1, !GetAZs ''] - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-private-2 - - Key: env - Value: !Ref env - - Key: Tier - Value: Private - - NatGateway: - Type: AWS::EC2::NatGateway - Properties: - AllocationId: !GetAtt NatGatewayEIP.AllocationId - SubnetId: !Ref PublicSubnet1 - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-nat - - Key: env - Value: !Ref env - - PublicRouteTable: - Type: AWS::EC2::RouteTable - Properties: - VpcId: !Ref SDPVPC - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-public-rt - - Key: env - Value: !Ref env - - PrivateRouteTable: - Type: AWS::EC2::RouteTable - Properties: - VpcId: !Ref SDPVPC - Tags: - - Key: Name - Value: !Sub ${env}-${AWS::StackName}-private-rt - - Key: env - Value: !Ref env - - PublicRoute: - Type: AWS::EC2::Route - DependsOn: AttachGateway - Properties: - RouteTableId: !Ref PublicRouteTable - DestinationCidrBlock: 0.0.0.0/0 - GatewayId: !Ref InternetGateway - - PrivateRoute: - Type: AWS::EC2::Route - Properties: - RouteTableId: !Ref PrivateRouteTable - DestinationCidrBlock: 0.0.0.0/0 - NatGatewayId: !Ref NatGateway - - PublicSubnet1RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: !Ref PublicSubnet1 - RouteTableId: !Ref PublicRouteTable - - PublicSubnet2RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: !Ref PublicSubnet2 - RouteTableId: !Ref PublicRouteTable - - PrivateSubnet1RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: !Ref PrivateSubnet1 - RouteTableId: !Ref PrivateRouteTable - - PrivateSubnet2RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: !Ref PrivateSubnet2 - RouteTableId: !Ref PrivateRouteTable - - PublicALB: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Type: application - Scheme: internet-facing - SecurityGroups: - - !Ref PublicALBSecurityGroup - Subnets: - - !Ref PublicSubnet1 - - !Ref PublicSubnet2 - - PrivateALB: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Type: application - Scheme: internal - SecurityGroups: - - !Ref PrivateALBSecurityGroup - Subnets: - - !Ref PrivateSubnet1 - - !Ref PrivateSubnet2 - - HTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref PublicALB - Port: 80 - Protocol: HTTP - DefaultActions: - - Type: redirect - RedirectConfig: - Protocol: HTTPS - Port: '443' - StatusCode: HTTP_301 - - HTTPSListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref PublicALB - Port: 443 - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref CertificateArn - DefaultActions: - - Type: fixed-response - FixedResponseConfig: - ContentType: text/plain - MessageBody: "Not Found" - StatusCode: 404 - - PrivateHTTPSListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref PrivateALB - Port: 443 - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref CertificateArn - DefaultActions: - - Type: fixed-response - FixedResponseConfig: - ContentType: text/plain - MessageBody: "Not Found" - StatusCode: 404 - - # Public ALB Security Group - PublicALBSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: Security group for public ALB - VpcId: !Ref SDPVPC - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 80 - ToPort: 80 - CidrIp: 0.0.0.0/0 - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIp: 0.0.0.0/0 - SecurityGroupEgress: - - IpProtocol: -1 - FromPort: -1 - ToPort: -1 - CidrIp: 0.0.0.0/0 - - PrivateALBSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: Security group for private ALB - VpcId: !Ref SDPVPC - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - CidrIp: !Ref VPCCidr # Accept traffic from within VPC - SecurityGroupEgress: - - IpProtocol: -1 - FromPort: -1 - ToPort: -1 - CidrIp: 0.0.0.0/0 - - ECSServicesSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: Security group for ECS services - VpcId: !Ref SDPVPC - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 0 - ToPort: 65535 - SourceSecurityGroupId: !Ref PublicALBSecurityGroup - - IpProtocol: tcp - FromPort: 0 - ToPort: 65535 - CidrIp: !Ref VPCCidr # Accept traffic from within VPC - SecurityGroupEgress: - - IpProtocol: -1 - FromPort: -1 - ToPort: -1 - CidrIp: 0.0.0.0/0 - -Outputs: - - VPCId: - Description: VPC ID - Value: !Ref SDPVPC - Export: - Name: !Sub ${AWS::StackName}-vpc-id - - PublicSubnet1Id: - Description: Public Subnet 1 ID - Value: !Ref PublicSubnet1 - Export: - Name: !Sub ${AWS::StackName}-public-subnet-1 - - PublicSubnet2Id: - Description: Public Subnet 2 ID - Value: !Ref PublicSubnet2 - Export: - Name: !Sub ${AWS::StackName}-public-subnet-2 - - PrivateSubnet1Id: - Description: Private Subnet 1 ID - Value: !Ref PrivateSubnet1 - Export: - Name: !Sub ${AWS::StackName}-private-subnet-1 - - PrivateSubnet2Id: - Description: Private Subnet 2 ID - Value: !Ref PrivateSubnet2 - Export: - Name: !Sub ${AWS::StackName}-private-subnet-2 - - PublicALBDNSName: - Value: !GetAtt PublicALB.DNSName - Export: - Name: !Sub ${AWS::StackName}-public-alb-dns - - PrivateALBDNSName: - Value: !GetAtt PrivateALB.DNSName - Export: - Name: !Sub ${AWS::StackName}-private-alb-dns - - HTTPSListenerArn: - Value: !Ref HTTPSListener - Export: - Name: !Sub ${AWS::StackName}-https-listener-arn - - PrivateHTTPSListenerArn: - Value: !Ref PrivateHTTPSListener - Export: - Name: !Sub ${AWS::StackName}-private-https-listener-arn - - PublicALBSecurityGroupId: - Description: Public ALB Security Group ID - Value: !Ref PublicALBSecurityGroup - Export: - Name: !Sub ${AWS::StackName}-public-alb-sg - - PrivateALBSecurityGroupId: - Description: Private ALB Security Group ID - Value: !Ref PrivateALBSecurityGroup - Export: - Name: !Sub ${AWS::StackName}-private-alb-sg - - ECSServicesSecurityGroupId: - Description: ECS Services Security Group ID - Value: !Ref ECSServicesSecurityGroup - Export: - Name: !Sub ${AWS::StackName}-ecs-services-sg - - VPCCidr: - Description: VPC CIDR Block - Value: !Ref VPCCidr - Export: - Name: !Sub ${AWS::StackName}-vpc-cidr - - PublicALBHostedZoneID: - Value: !GetAtt PublicALB.CanonicalHostedZoneID - Export: - Name: !Sub ${AWS::StackName}-public-alb-hosted-zone - - PrivateALBHostedZoneID: - Value: !GetAtt PrivateALB.CanonicalHostedZoneID - Export: - Name: !Sub ${AWS::StackName}-private-alb-hosted-zone \ No newline at end of file From 426a063262976f682a55daf974e9c266d6bdaa6b Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Tue, 28 Jan 2025 14:06:33 -0800 Subject: [PATCH 08/11] remove bastion temporarily --- resources/aws/cloudformation/bastion-eks.yaml | 143 ------------------ 1 file changed, 143 deletions(-) delete mode 100644 resources/aws/cloudformation/bastion-eks.yaml diff --git a/resources/aws/cloudformation/bastion-eks.yaml b/resources/aws/cloudformation/bastion-eks.yaml deleted file mode 100644 index 48013b217..000000000 --- a/resources/aws/cloudformation/bastion-eks.yaml +++ /dev/null @@ -1,143 +0,0 @@ -Parameters: - env: - Type: String - Default: "dev" - AllowedValues: - - dev - - staging - - prod - - KeyName: - Type: AWS::EC2::KeyPair::KeyName - Description: Name of an existing EC2 KeyPair for SSH access - - NetworkStackName: - Type: String - Default: "sdp-network" - Description: Name of the network stack containing VPC and subnet exports - - DatabaseStackName: - Type: String - Default: "sdp-database" - Description: Name of the database stack containing RDS endpoint and credentials - - EksStackName: - Type: String - Default: "sdp-eks" - Description: Name of the EKS stack containing cluster and service exports - -Resources: - BastionSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: Security group for database bastion host - VpcId: !ImportValue - Fn::Sub: ${NetworkStackName}-vpc-id - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 22 - ToPort: 22 - CidrIp: 0.0.0.0/0 - Description: "Allow SSH inbound" - - IpProtocol: tcp - FromPort: 2345 - ToPort: 2345 - CidrIp: 0.0.0.0/0 - Description: "Allow Delve debugger connections" - SecurityGroupEgress: - - IpProtocol: -1 - FromPort: -1 - ToPort: -1 - CidrIp: 0.0.0.0/0 - Tags: - - Key: Name - Value: !Sub ${env}-db-bastion-sg - - Key: env - Value: !Ref env - - BastionHost: - Type: AWS::EC2::Instance - DependsOn: BastionSecurityGroup - Properties: - InstanceType: t2.micro - ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}' - KeyName: !Ref KeyName - SubnetId: !ImportValue - Fn::Sub: ${NetworkStackName}-public-subnet-1 - SecurityGroupIds: - - !Ref BastionSecurityGroup - UserData: - Fn::Base64: | - #!/bin/bash - dnf update -y - dnf install -y postgresql15 - dnf install -y curl jq - Tags: - - Key: Name - Value: !Sub ${env}-db-bastion - - Key: env - Value: !Ref env - - RDSIngressRule: - Type: AWS::EC2::SecurityGroupIngress - DependsOn: BastionSecurityGroup - Properties: - GroupId: !ImportValue - Fn::Sub: ${DatabaseStackName}-db-sg - IpProtocol: tcp - FromPort: 5432 - ToPort: 5432 - SourceSecurityGroupId: !Ref BastionSecurityGroup - Description: "Allow PostgreSQL from Bastion Host" - - EksClusterIngressRule: - Type: AWS::EC2::SecurityGroupIngress - DependsOn: BastionSecurityGroup - Properties: - GroupId: !ImportValue - Fn::Sub: ${EksStackName}-cluster-sg - IpProtocol: tcp - FromPort: 443 - ToPort: 443 - SourceSecurityGroupId: !Ref BastionSecurityGroup - Description: "Allow HTTPS access to EKS cluster from Bastion Host" - -Outputs: - BastionPublicIP: - Description: Public IP of the Bastion Host - Value: !GetAtt BastionHost.PublicIp - - SSHCommand: - Description: Command to SSH to bastion host - Value: !Sub "ssh -i ${KeyName}.pem ec2-user@${BastionHost.PublicIp}" - - DatabaseTunnelCommand: - Description: Command to create SSH tunnel for PostgreSQL - Value: !Sub - - "ssh -N -L 5432:${dbEndpoint}:5432 -i ${KeyName}.pem ec2-user@${BastionHost.PublicIp}" - - dbEndpoint: !ImportValue - Fn::Sub: ${DatabaseStackName}-db-endpoint - - PSQLCommand: - Description: PSQL connection command (after tunnel is established) - Value: !Sub - - "psql -h localhost -U ${dbuser} -d ${dbname}" - - dbuser: !ImportValue - Fn::Sub: ${DatabaseStackName}-dbusername - dbname: !ImportValue - Fn::Sub: ${DatabaseStackName}-db-name - - TenantApiCommand: - Description: Command to access tenant API through local port forwarding - Value: !Sub - - | - # First establish port forwarding - kubectl port-forward pod/sdp 8003:8003 - - # Then in another terminal, use the API - curl -X POST http://localhost:8003/tenants/ \ - -H "Content-Type: application/json" \ - -H "Authorization: Basic $(echo -n 'admin:api_key_1234567890' | base64)" \ - -d '{"name": "acmeorg", "owner_email": "john@stellar.org", "owner_first_name": "john", "owner_last_name": "doe", "organization_name": "acmeorg"}' - - podName: !ImportValue - Fn::Sub: ${EksStackName}-sdp-pod-name \ No newline at end of file From e083b45e48df3eafe9633cbd480cdab0fbc8fa47 Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Tue, 28 Jan 2025 14:15:39 -0800 Subject: [PATCH 09/11] documentation update --- resources/aws/cloudformation/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/aws/cloudformation/README.md b/resources/aws/cloudformation/README.md index 311cb8b7d..372eed5dc 100644 --- a/resources/aws/cloudformation/README.md +++ b/resources/aws/cloudformation/README.md @@ -101,7 +101,9 @@ aws cloudformation create-stack \ --capabilities CAPABILITY_NAMED_IAM \ --parameters \ ParameterKey=env,ParameterValue=dev \ - ParameterKey=namespace,ParameterValue=sdp + ParameterKey=namespace,ParameterValue=sdp \ + ParameterKey=RecaptchaSiteSecretKey,ParameterValue=YOUR_RECAPTCHA_SITE_SECRET_KEY \ + ParameterKey=RecaptchaSiteKey,ParameterValue=YOUR_RECAPTCHA_SITE_KEY ``` **Note**: Leave the following parameters empty to auto-generate new keys: From c94e20a16a73ce056390f761857de6274e5161e3 Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Tue, 28 Jan 2025 14:27:44 -0800 Subject: [PATCH 10/11] updated documentation --- resources/aws/cloudformation/README.md | 47 +++----------------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/resources/aws/cloudformation/README.md b/resources/aws/cloudformation/README.md index 372eed5dc..2db71ac02 100644 --- a/resources/aws/cloudformation/README.md +++ b/resources/aws/cloudformation/README.md @@ -315,7 +315,9 @@ kubectl apply -f eks-helm/cluster-issuer.yaml ``` ## 6. Install External-DNS -```bash +Replace the domainFilters with your registered domain below. + +```bashd # Add and update repository helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/ helm repo update @@ -343,47 +345,8 @@ kubectl get pods -n external-dns helm repo add stellar https://helm.stellar.org ``` -### Update your Values file with the Distribution Account Public Key -replace `YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY` with the distribution account public key stored in Secrets Manager - -```yaml -ASSETS_VALUE: | - { - "assets": [ - { - "sep24_enabled": true, - "schema": "stellar", - "code": "USDC", - "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", - "significant_decimals": 7, - "deposit": { - "enabled": true, - "fee_minimum": 0, - "fee_percent": 0, - "min_amount": 1, - "max_amount": 10000 - }, - "withdraw": {"enabled": false} - }, - { - "sep24_enabled": true, - "schema": "stellar", - "code": "native", - "distribution_account": "YOUR_DISTRIBUTION_ACCOUNT_PUBLIC_KEY", - "significant_decimals": 7, - "deposit": { - "enabled": true, - "fee_minimum": 0, - "fee_percent": 0, - "min_amount": 1, - "max_amount": 10000 - }, - "withdraw": {"enabled": false} - } - ] - } -``` +### Modify Values File +Replace occurrences of "mystellarsdpdomain.org" in [values-dev.yaml](aws/cloudformation/values-dev.yaml) with your registered domain. ### Install SDP From d457fa9c29b049a00d3f064dca44e8c5823b4f7f Mon Sep 17 00:00:00 2001 From: Reece Markowsky Date: Thu, 30 Jan 2025 22:26:36 -0800 Subject: [PATCH 11/11] aws sns config --- resources/aws/cloudformation/.out.swp | Bin 0 -> 24576 bytes resources/aws/cloudformation/README.md | 53 +++++++++++++++++- .../eks-helm/sdp-secrets-dev.yaml | 15 ++--- .../cloudformation/eks-helm/values-dev.yaml | 8 ++- .../aws/cloudformation/sdp-keys-eks.yaml | 42 +++++++++++++- 5 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 resources/aws/cloudformation/.out.swp diff --git a/resources/aws/cloudformation/.out.swp b/resources/aws/cloudformation/.out.swp new file mode 100644 index 0000000000000000000000000000000000000000..62c01d51e4aab9e7065326561c8ae9c2f3e18cbc GIT binary patch literal 24576 zcmeHPe~cVe9bZu?6+sI`1xa{pO=z*ZH?zNP_sFW(>sczjYrVZvYOmSM&b+-HZgysw zA9oyy5G5v}NdGX#P%%VFkSK}K#Dr*+R?r}VKLAlc)V9>BsI3J=@#pu=yt&=`-rVl& z-O^sux#pX@&S&R+zwi6r`@Zk@`@U~0!nIpQNFgc2;OFhJ*yj&_Ve$Rk~bR0RARenBr-|OkR@&Y=Wm|hV4p&#`z)Jknq(#v z)v7qAMe9_z6AewWtA<%mR3v$d>Pn)tX?sG<6vTw3G!n9AI0}O$TQ&4PlUjyjf&hKe zjMaxg!?EYf5dAOGz!|9l$F3&w=j}+RM0csLjbBbKykN%}sfwu6kp?0SL>h=R5NRON zK%{|41Ca*KR1MgTO|e^`^Jj4d#QEW-$D2b9Dg^TS5G1Q zFvr(${20Oyar`2V$KL4u;p^`p$Is>XMF{^L$Is*VWeEQ*$KS#64G8}Y$Nl-W5#i5s z+_w+A5&mn0I|zRcwZ9kP&m#Ojgg=AYKY;LGA^bUn|B~Yu@czGo@TWQc7LKoallO{H{RwlN^65Z~rQUKf!T-{%%J2&pGaoPZ{AqYVKgw}m|3?u1BlP|;gg?S@fBwIQ z@Hcb0{PA1GANb?TKOQ@qf9_I*|B$!ukI&@@{{g}a2!EL4{`&ba!XHBKPa*vK9QVin zR)ilw_+1F!kJ|qh!XHHV;|TvA$9?@BK{!`i^efUpq=85Skp?0SL>f2=8jzG&Y$NbF z#CXB^f1LCD_S@k6ALtUG+s}{1E(ZE0I7fp(N5KjG1kgD^_klx}0D1%*F9~Qh&{tQ- zV%vaDoD+-f1IhqBuqqalfz|-+2Pf%zp#9(jTn6+paGstAe>x9zC&V>J!Kq^LFO%sY zmuKm}Y_(2{@syCtCIm5&7RFP;K&mhx6q1=-_9Jnk(P^p`RlRDEx;0shmu$(jReh3J za*ZmEMoluK+BK3TGln@uO)Hs9#z{j}iejwWwoN*zLdAp0n!nzt5Zh?svRjwxbbwe; z@K83PqC%afW_d=^G-_LARi9REx8R`+FYehucB?uxG%aZZL=-Idfi>c2wmMFANw)`x zZ8~(%>nUhMvgKM?(&d_Ami>~AvTaJbCCRKb!z#;0y#eCG-z!AoSyo?Cu9`-@Y&n&> zYJ(0}j6!)WOt~R>V%o+E6jD}AS)-?gjIf9dT~;-9k#&+3)jmcf>tHX3T1+_g?4s$u+h*|+0_pzfytw0I1Ajq zRnJWJu)z^(o2qQ}u*K5c2E@9p%Czf#&q$`u_8NC%8=eN+M>d)UY+_`5wn2$%kEB?MpE)O4>GKShG+<()A@i&zECwKbyAmX$E01z z9kS`IRGEZ<9d+szHUmsnTxs@B@~go*+yvt}q^U4lde?5?WEq31PYp~#@7N5wjttq( zYfs7G_ASdDg5!68_Df{<2(>I}l0r9JkBORl$XJUXD7)$+gF8#*(n!f&c5+S9b*d5g zfA9Lo8t1%hW5DOP)b_jS+NQBx<*^;3^SU-XGPq^yQkgGYHN$mD)mpp9d3MKPp1JgF z;zXRcG!ZAVDOok}tHZ9Flo)EokC#eh)5akKhTL_Vw;P5=*0Gp_Zz)CQ%C8U6m5>bG zFd<>Pal!)5A=n7vEZLw^SM>$$FRf=SEawffgDOE;#a~Du}#Z{XG7b@N@P&e zj2WtsZKet~+G5+CZ5X6M&AMt?5MB{USBP%dgn5c}2n`gfgo*8h{<(owXvN|CtG~a& zrs)Nhz-<8Jaz8Q=52M&-yUloXvuY24a4Lj!>0~M?glQ)?CttIjYaw)n?H0Ad;{RJA z=6(r?#s7YOejCL7_e0EoCD6SP^S=zS{w+Wk0(}GG{SN^hf>?h5=r)M;ABGtJ13-5` zeE$_5+p{x}S%~dlg}8nf5aV%z@riyS4V*d+1SM_Kg@H^VnN6qX7Ea5;9yOTJpUY~v zS({m1CM=CW=F$l4G2ByWw>&u)v6*&i;R4rY;1Y}Lh_lp?p9EN#tMH7RXT6n*C@8sp zA)$z=Tq09QXA@Gtq$Dy@PO8wfn35EUfKTS7u1G3`biu|A?&mZ;c8PoJU{IO$lnD2< z`ST8bCw~a*jYxnE)_JH+3wg( zCX%}6oRS%dkELT9>|zyM-qL1aUxaKVj2tWgc+F2rlKzxbO;xg$L@J*WV6H)4wNlMz z5-BB@uLzPLWYSeqp|a#y)P2)1Cna6I$&KN!u)zKGvYTYfTvijFvBW1l@v@q1v({BD z>gIrFG&1>A&}i=7&XTZR=;B8%5ZL*)3LFQXf91jT9^y0<7zS9HUY3XWiQ85aM=UUJ z;5bRPJ4J=&$b0GNbyiz%w8s)pf{77)d&pckmZM;%GQ{NQZ)TQSOf4j|yh-j&aHVxY zz`Ro^%U@4RHh6;&0x|;!KBlU0Pm`|(G^hQ=(VD4umyZHZyg6M~q*+&fzj>nCZQV_- z$o{6k-O>qU58c=@Y&L!wmM0TN>tO^AbI!30In!a}4BUu^^&1@Ouq6WfFr3GDH&p$E zZ5e0fd&Q^2hSn=Ki~AM5;t*zFd&R4(S>J(a8cqZYfiq&ITG?Joyi_ae$`I%_pDdSg zaS4!#?6AU?VQf0NjIM}*?idoWtNFYPf#>{37XObyeE)GE7XSP8i~At{Uk7vm;{RPh zFZiE1b#Yt7InqF+fk*?91|kha8i+IyX&}--q=85Sr@00KkE8MfBCAgh%wD4W)Djaq zU2*85(6?=pr3uC=lcEBG9cs=L6jjEWg&p>Wx+kFXZedLA{95UcZUE;-+{T4P*mza=}ZtN6qv` zJ?UnpP>TgvnR#l@W~GH7E7`roOUqMxGNb}6^@0@aVwXggk#B8(8pWjxJmEb#S@d=i zApLaMFqfgE_D74Jh+^QxMTfFGi^-RP~6^ap|-V}-& zd6|t-B{r+tpNJ1_85`O*OS!5*bgM>H=?q=2pOAef#sXc5CTCopy^trD(xB614 zN=mHcX+n@QP`4@M~3<=-;)CG zJ+n;(be3;cP&9Q0qIh?z=X6#xEW60Q&7FV6d$K;u2Miu6P@SdfNvN{cY*Nh{Z=c3(E#pG@b-x@)c;AKAKrXzCOto2fiytS3V?C{m_< UVj6A^uz#c^RV7p9uf${j2bMLd)&Kwi literal 0 HcmV?d00001 diff --git a/resources/aws/cloudformation/README.md b/resources/aws/cloudformation/README.md index 2db71ac02..1308a5c9d 100644 --- a/resources/aws/cloudformation/README.md +++ b/resources/aws/cloudformation/README.md @@ -17,7 +17,7 @@ This guide walks through deploying the Stellar Disbursement Platform (SDP) infra - Deploys RDS PostgreSQL database in private subnet - Creates necessary database secrets in AWS Secrets Manager -- Keys Stack (sdp-keys.yaml) [Optional] +- Keys Stack (sdp-keys-eks.yaml) [Optional] - Manages Stellar and encryption keys by either: - Using provided keys via parameters, or - Auto-generating keys using Lambda function for dev/test environments @@ -97,7 +97,7 @@ Deploy the secrets and keys management stack: ```bash aws cloudformation create-stack \ --stack-name sdp-keys-eks \ - --template-body file://sdp-keys.yaml \ + --template-body file://sdp-keys-eks.yaml \ --capabilities CAPABILITY_NAMED_IAM \ --parameters \ ParameterKey=env,ParameterValue=dev \ @@ -351,13 +351,60 @@ Replace occurrences of "mystellarsdpdomain.org" in [values-dev.yaml](aws/cloudfo ### Install SDP ```bash -helm install sdp stellar/stellar-disbursement-platform -f eks-helm/values.yaml --namespace sdp +helm install sdp stellar/stellar-disbursement-platform -f eks-helm/values-dev.yaml --namespace sdp ``` ### Verify Pods are healthy ``` kubectl -n sdp get pods ``` +## Adding a tenant from the SDP Pod + +### Get the SDP Pod name and exec to its shell +```bash +kubectl -n sdp get pods + +reecemarkowsky  …/cloudformation   reece/SDP-1491-sdp-cloudformation ● ?  kubectl -n sdp get pods  ✔  11:30:38 +NAME READY STATUS RESTARTS AGE +sdp-5bddb74b4d-skqsv 1/1 Running 0 13m +sdp-ap-58b6cc978-8q4sg 1/1 Running 0 13m +sdp-dashboard-7799755844-nwnw5 1/1 Running 0 13m +sdp-tss-84bc97659-bf9pb 1/1 Running 0 13m + +kubectl -n sdp exec -it sdp-5bddb74b4d-skqsv -- /bin/bash +``` +#### Install curl and use the /tenant endpoint to add a tenant +```bash +Setting up curl (8.5.0-2ubuntu10.6) ... +Processing triggers for libc-bin (2.39-0ubuntu8.3) ... +root@sdp-5bddb74b4d-skqsv:/app# curl --location 'http://localhost:8003/tenants/' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic cmVlY2VAc3RlbGxhci5vcmc6YWRtaW4tYXBpLWtleQ==' \ +--data-raw '{ + "name": "ridedash", + "owner_email": "reece@stellar.org", + "owner_first_name": "reece", + "owner_last_name": "markowsky", + "organization_name": "aid-retreat", + "sdp_ui_base_url": "https://ridedash.mystellarsdpdomain.org", + "base_url": "https://ridedash.mystellarsdpdomain.org", + "distribution_account_type": "DISTRIBUTION_ACCOUNT.STELLAR.DB_VAULT" +}' +{ + "id": "db10d670-d126-4935-a7ad-4a6abe312ada", + "name": "ridedash", + "base_url": "https://ridedash.mystellarsdpdomain.org", + "sdp_ui_base_url": "https://ridedash.mystellarsdpdomain.org", + "status": "TENANT_PROVISIONED", + "is_default": false, + "created_at": "2025-01-30T19:30:15.315509Z", + "updated_at": "2025-01-30T19:30:16.711518Z", + "deleted_at": null, + "distribution_account_address": "GCKNCA7EZYZEQNQR22XGL47WCRL3VVDQDKLF7DOIK6O3Y5TLBAWQYQWA", + "distribution_account_type": "DISTRIBUTION_ACCOUNT.STELLAR.DB_VAULT", + "distribution_account_status": "ACTIVE" +}root@sdp-5bddb74b4d-skqsv:/app# +``` ## Troubleshooting diff --git a/resources/aws/cloudformation/eks-helm/sdp-secrets-dev.yaml b/resources/aws/cloudformation/eks-helm/sdp-secrets-dev.yaml index 025633d35..d63d6cc93 100644 --- a/resources/aws/cloudformation/eks-helm/sdp-secrets-dev.yaml +++ b/resources/aws/cloudformation/eks-helm/sdp-secrets-dev.yaml @@ -78,12 +78,9 @@ spec: - secretKey: ADMIN_API_KEY remoteRef: key: /sdp/dev/ADMIN_API_KEY - - - - - - - - - \ No newline at end of file + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + key: /sdp/dev/AWS_ACCESS_KEY_ID + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + key: /sdp/dev/AWS_SECRET_ACCESS_KEY diff --git a/resources/aws/cloudformation/eks-helm/values-dev.yaml b/resources/aws/cloudformation/eks-helm/values-dev.yaml index e43259018..5b76d9cf2 100644 --- a/resources/aws/cloudformation/eks-helm/values-dev.yaml +++ b/resources/aws/cloudformation/eks-helm/values-dev.yaml @@ -42,15 +42,19 @@ sdp: DATABASE_URL: "/sdp/dev/DATABASE_URL" RECAPTCHA_SITE_KEY: "/sdp/dev/RECAPTCHA_SITE_KEY" RECAPTCHA_SITE_SECRET_KEY: "/sdp/dev/RECAPTCHA_SITE_SECRET_KEY" + AWS_SECRET_ACCESS_KEY: "/sdp/dev/AWS_SECRET_ACCESS_KEY" + AWS_ACCESS_KEY_ID: "/sdp/dev/AWS_ACCESS_KEY_ID" # =========================== START sdp.configMap =========================== configMap: data: + AWS_SNS_SENDER_ID: "" + AWS_REGION: "us-west-2" ADMIN_ACCOUNT: "reece@stellar.org" ENVIRONMENT: "dev" LOG_LEVEL: "debug" METRICS_TYPE: "PROMETHEUS" EMAIL_SENDER_TYPE: "DRY_RUN" - SMS_SENDER_TYPE: "DRY_RUN" + SMS_SENDER_TYPE: "AWS_SMS" ENABLE_MFA: "false" NETWORK_PASSPHRASE: "Test SDF Network ; September 2015" HORIZON_URL: "https://horizon-testnet.stellar.org" @@ -246,4 +250,4 @@ dashboard: - hosts: - 'dashboard.mystellarsdpdomain.org' - '*.dashboard.mystellarsdpdomain.org' - secretName: sdp-dashboard-cert \ No newline at end of file + secretName: sdp-dashboard-cert diff --git a/resources/aws/cloudformation/sdp-keys-eks.yaml b/resources/aws/cloudformation/sdp-keys-eks.yaml index 027c52548..f80f2635f 100644 --- a/resources/aws/cloudformation/sdp-keys-eks.yaml +++ b/resources/aws/cloudformation/sdp-keys-eks.yaml @@ -131,6 +131,25 @@ Parameters: Default: "YOUR_RECAPTCHA_SECRET_KEY" Description: "Environment variable: RECAPTCHA_SITE_SECRET_KEY" + AwsSnsSenderId: + Type: String + NoEcho: true + Default: "AWS_SNS_SENDER_ID" + Description: "Environment variable: AWS_SNS_SENDER_ID" + + AwsSecretAccessKey: + Type: String + NoEcho: true + Default: "AWS_SECRET_ACCESS_KEY" + Description: "Environment variable: AWS_SECRET_ACCESS_KEY" + + AwsAccessKeyId: + Type: String + NoEcho: true + Default: "AWS_ACCESS_KEY_ID" + Description: "Environment variable: AWS_ACCESS_KEY_ID" + + Conditions: GenerateSep10Keys: !Equals [ !Ref Sep10SigningPrivateKey, "" ] GenerateDistributionKeys: !Equals [ !Ref DistributionSeed, "" ] @@ -443,6 +462,27 @@ Resources: Description: "Recaptcha site secret key" SecretString: !Ref RecaptchaSiteSecretKey + AwsSnsSenderIdSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/AWS_SNS_SENDER_ID + Description: "Recaptcha site secret key" + SecretString: !Ref AwsSnsSenderId + + AwsSecretAccessKeySm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/AWS_SECRET_ACCESS_KEY + Description: "Recaptcha site secret key" + SecretString: !Ref AwsSecretAccessKey + + AwsAccessKeyIdSm: + Type: AWS::SecretsManager::Secret + Properties: + Name: !Sub /sdp/${env}/AWS_ACCESS_KEY_ID + Description: "Recaptcha site secret key" + SecretString: !Ref AwsAccessKeyId + Outputs: Sep10SigningPrivateKeySmArn: Value: !Ref Sep10SigningPrivateKeySm @@ -544,4 +584,4 @@ Outputs: Value: !Ref RecaptchaSiteSecretKeySm Export: Name: !Sub ${AWS::StackName}-recaptcha-site-secret-key-sm-arn - Description: "ARN for RECAPTCHA_SITE_SECRET_KEY secret" \ No newline at end of file + Description: "ARN for RECAPTCHA_SITE_SECRET_KEY secret"