This small sample application uses a SpringBoot service with Spring Cloud AWS to source certain configuration elements. Additionally, it uses the AWS Cloud Development Kit (CDK) to provision the AWS resources that the application needs to deploy into AWS.
This project defines a simple SpringBoot service that connects to a Postgres database. The
deployment will handle the provisioning of credentials, such as passwords and certificates. The
application will resolve the credentials differently depending on its deployed environment. The
SpringBoot application uses Spring profiles to determine the right strategy. When using the local
or docker
profiles, it will use the Spring
configtree
to resolve the credentials. In AWS, the aws
profile is used and the
Spring Cloud AWS library
handles the resolution of secrets.
When deployed to AWS, a codebuild job populates the database using the
Flyway CLI. A
Lambda trigger triggers the CodeBuild project whenever
the data-migration.zip
file is uploaded to S3. When running under Docker Compose, we leverage the
Postgres containers bootstrap mechanism to create the table and provide data.
This project is structured as a single project that builds and deploys all assets when deployed to either docker-compose or in AWS.
A vital element of this project is to promote proper credential handling. As such, the project
attempts to simulate a hands-off credentials management approach. The DB credentials are generated
and stored in the ./credentials
directory in a local environment. When running under Docker
Compose, these values are injected into the environment via the Docker Secrets mechanism. When
deployed in AWS, the DB credentials are generated by AWS Secrets Manager and referenced in the
application via Spring Cloud AWS. Before running the application in either local model, run the
prepare_credentials.sh
script. This will generate the following:
- The Postgres root password
- The Postgres appuser password (used by the SpringBoot application)
- The Postgres certificates
- A KeyStore that contains the self-signed Postgres root CA
- A Keystore that contains the RDS certs for us-east-1.
You will only use these credentials locally except for the Keystore for RDS. When deployed to AWS, the credentials generated by AWS Secrets Manager are used.
Practically ALL SpringBoot/Postgres examples create a JDBC connection with sslMode=DISABLED
as it
is generally more accessible but fundamentally wrong. Because these examples make their way into
production, this project demonstrates using TLS with Postgres.
The Postgres certificates are generated at startup so we can prepare a KeyStore with the generated root certificates to make a TLS connection work locally. When deployed to AWS, the application will use the Keystore that contains the RDS certificates.
In this model, we use Docker Compose to bring up ONLY the Postgres DB so that we can run the SpringBoot application via an IDE on the Host OS. To do this, run the following:
$ ./prepare_credentials.sh
$ docker compose up postgres
In your IDE, use the local
profile to connect to the database.
To run the stack locally, simply run the following commands:
$ ./prepare_credentials.sh
$ docker compose build
$ docker compose up
This will build the container with the SpringBoot application and launch the Postgres database and
SpringBoot application. The depends_on
attribute of Docker Compose does not force the SpringBoot
app to wait until the Postgres instance is ready for requests. Upon running the stack for the first
time, it is normal to see the SpringBoot app fail to connect to Postgres in the first few attempts.
The SpringBoot app has a restart
policy of always
which will restart the app on failure.
Eventually, the application will stabilize, and you should be able to hit the following URIs:
http://localhost:8081/actuator/info
http://localhost:8081/actuator/health
Before deploying to AWS, run the build target:
npm run build
And then synthesize the stack by running:
npx cdk synth
And finally, deploy the stack:
npx cdk deploy --all
or if you don't want to deal with the prompts, run:
npm run deploy
Once deployed, the AWS environment can be verified to ensure specific resources have been created and have been configured inline with expectations. The project uses CINC Auditor/InSpec to
cinc-auditor exec verification -t aws://
or with InSpec:
inspec exec verification -t aws://