Post-Deployment
The stack reports success before the platform is ready, so the work isn't quite finished when CloudFormation goes green. What's left divides neatly in two. First we read the outputs and the secrets to find out where everything landed, then we watch the bootstrap finish on the instance itself. Anyone running with EnableHttps set to true has one extra job, because the certificate points at a DNS name that doesn't resolve to the instance yet.
Start with the outputs.
1. Read the stack outputs
There are 13 outputs, four of which appear only under the right conditions.
aws cloudformation describe-stacks --stack-name yeedu-platform \
--query 'Stacks[0].Outputs' --output table
| Output | Condition | Value |
|---|---|---|
VpcId | always | The VPC you passed in. |
Ec2SubnetId | always | The EC2 and EFS subnet. |
RdsSubnetIds | RdsCreate is true | Both RDS subnet IDs, comma-joined. |
InstanceId | always | The YeeduInstance instance ID. |
InstancePrivateIp | always | Private IPv4 address of the instance. |
InstancePublicIp | AssignPublicIp is true | Public IPv4 address. |
InstanceElasticIp | AssignPublicIp is true | The allocated Elastic IP. |
ApplicationEndpoint | always | CustomDnsName with HTTPS on, otherwise the public or private DNS name of the instance. |
RdsEndpoint | always | Database address, or the literal string Not Created. |
S3BucketName | always | ${AWS::StackName}-data. |
EfsId | always | The EFS file system ID. |
YeeduUserAccessKey | always | Access key ID for the generated IAM user. |
YeeduUserSecretKey | always | Secret access key for that user. |
That last output is a live secret access key sitting in plain text in the stack outputs. Anyone with cloudformation:DescribeStacks on this stack can read it. The same pair is stored properly in Secrets Manager, so we'd treat the output as something to lock down with IAM rather than something to copy around.
2. Point DNS at the instance, if you enabled HTTPS
With EnableHttps set to true, the bootstrap writes CustomDnsName into the REST API, UI, history server and functions proxy hostnames, and copies your certificate and key out of S3 into /opt/Core-Services-Formation/ssl as yeedu.crt and yeedu.key. Nothing creates the DNS record for you. Create an A record for that name pointing at the Elastic IP from InstanceElasticIp, or a CNAME to the instance DNS name, and the certificate will match what browsers actually request.
3. Read the secrets
Three secrets are created, and two of them are named predictably from the stack name and environment.
# IAM access key pair used by the platform
aws secretsmanager get-secret-value \
--secret-id yeedu-platform-dev-yeedu-config-secret \
--query SecretString --output text
# Database endpoint, port, user, password and database name
aws secretsmanager get-secret-value \
--secret-id yeedu-platform-dev-yeedu-rds-secret \
--query SecretString --output text
YeeduDbSecret holds the generated master password and gets an AWS-assigned name rather than one from the template. Its username field is yeedu, and the password is 16 characters generated with a long exclusion list, so no shell-hostile characters end up in it. When RdsCreate is false, every field in the RDS secret is written as an empty string, and the bootstrap skips writing yeedu-connection.properties altogether, leaving the platform on its packaged database configuration.
4. Confirm the bootstrap finished
SSH to the instance using the key pair named in Ec2KeyName, then read the log. Everything the user data script does is teed to /var/log/bootstrap.log, including the AWS CLI v2 install and the Docker Compose 1.29.2 download.
sudo tail -f /var/log/bootstrap.log
If you'd rather not log in, the CloudWatch agent installed during boot ships /var/log/cloud-init-output.log to the yeedu_userdata_logs group, so the same story is readable from the console. That group only exists when CreateLogGroups is true, or when it was retained from an earlier stack.
The script finishes by running ./yeedu-core-services.sh start from /opt/Core-Services-Formation. Three files there are worth checking, since they're generated from your parameters and the two secrets.
| File | What it holds |
|---|---|
/etc/yeedu-env | AWS credentials and region, account ID, S3 bucket, EFS ID and DNS name, RDS connection values, public and HTTPS flags. |
/opt/Core-Services-Formation/yeedu-system-config.properties | Registry provider and URL, cloud provider, project ID, object storage bucket, NFS hostname and mount target. |
/opt/Core-Services-Formation/yeedu-connection.properties | PostgreSQL host, port, database, user and password, plus the hostnames and SSL flags for each service. Written only when an RDS endpoint is present. |
sudo docker ps
Every service should be listed and running.
5. Tighten the security group
The instance security group ships wide open. Every rule below uses 0.0.0.0/0 as its source, which is deliberate for a quick evaluation and much too permissive for anything else, so restricting these to your own CIDR ranges is the first hardening step we'd take on a stack that's going to stay up.
| Port | Service |
|---|---|
| 22 | SSH |
| 80, 443 | HTTP and HTTPS |
| 389 | LDAP |
| 3000 | Grafana |
| 5172 | Functions service |
| 5173 | Yeedu UI |
| 5432 | PostgreSQL |
| 5672, 15672 | RabbitMQ messaging and management UI |
| 6379 | Redis |
| 8080 | REST API |
| 8081 | Airflow UI |
| 8086 | InfluxDB |
| 8200 | Vault API |
| 8765 | Proxy cacher |
| 8888-9088 | Jupyter workspaces |
| 10000 | History server |
The database and file system groups are already tight. Both accept traffic only from the EC2 security group, PostgreSQL on 5432 and NFS on 2049.
One more thing worth reviewing. The bootstrap creates a yeedu operating system user with passwordless sudo and writes a Yeedu-supplied public key into its authorized_keys, which is how support reaches the box. Remove it if that isn't wanted.