From fbbf093553a4c323c218ead24dbc99335c1b5398 Mon Sep 17 00:00:00 2001 From: Buffden Date: Sun, 29 Mar 2026 00:07:21 -0500 Subject: [PATCH 1/3] fix(ci): prevent script injection by moving github.sha to env var in run steps --- .github/workflows/deploy.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index aae7039..ea2b101 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -110,17 +110,21 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker image + env: + IMAGE_TAG: ${{ github.sha }} run: | - docker build -t ghcr.io/buffden/tinyurl-api:${{ github.sha }} tinyurl/ - docker push ghcr.io/buffden/tinyurl-api:${{ github.sha }} + docker build -t ghcr.io/buffden/tinyurl-api:$IMAGE_TAG tinyurl/ + docker push ghcr.io/buffden/tinyurl-api:$IMAGE_TAG - name: Deploy via SSM RunCommand + env: + IMAGE_TAG: ${{ github.sha }} run: | COMMAND_ID=$(aws ssm send-command \ --instance-ids "$EC2_INSTANCE_ID" \ --document-name "AWS-RunShellScript" \ --parameters "commands=[ - \"export IMAGE_TAG=${{ github.sha }}\", + \"export IMAGE_TAG=$IMAGE_TAG\", \"export RDS_ENDPOINT=$RDS_ENDPOINT\", \"cd /app\", \"docker compose -f docker-compose.prod.yml pull\", From 0313d20de7db3992d4c7013a5fa9e245cd425489 Mon Sep 17 00:00:00 2001 From: Buffden Date: Sun, 29 Mar 2026 00:13:48 -0500 Subject: [PATCH 2/3] feat(db): add least-privilege app user separation for local and prod - Replace weak :-tinyurl fallbacks with :?required on all credential vars - Add SPRING_FLYWAY_USER/PASSWORD to backend service (Flyway keeps master) - Pass SPRING_DATASOURCE creds to postgres service for init script - Add 002_app_user.sh: creates tinyurl_appuser with DML-only grants on url_mappings - Add DB_LEAST_PRIVILEGE.md: full guide covering RDS and local setup - Add TROUBLESHOOTING_SSM_SESSION_MANAGER.md: documents all SSM access issues - Fix CORS: set allowCredentials(false) explicitly --- .github/workflows/deploy.yml | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ea2b101..100a701 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -43,17 +43,26 @@ jobs: needs: build-test runs-on: ubuntu-latest - env: - POSTGRES_USER: tinyurl_ci - POSTGRES_PASSWORD: ci_smoke_postgres_pass - SPRING_DATASOURCE_USERNAME: tinyurl_appuser_ci - SPRING_DATASOURCE_PASSWORD: ci_smoke_appuser_pass - SPRING_FLYWAY_USER: tinyurl_ci - SPRING_FLYWAY_PASSWORD: ci_smoke_postgres_pass - steps: - uses: actions/checkout@v4 + - name: Generate ephemeral CI credentials + run: | + PG_PASS=$(openssl rand -hex 16) + APP_PASS=$(openssl rand -hex 16) + echo "POSTGRES_USER=tinyurl_ci" >> $GITHUB_ENV + echo "POSTGRES_PASSWORD<> $GITHUB_ENV + echo "$PG_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "SPRING_DATASOURCE_USERNAME=tinyurl_appuser_ci" >> $GITHUB_ENV + echo "SPRING_DATASOURCE_PASSWORD<> $GITHUB_ENV + echo "$APP_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "SPRING_FLYWAY_USER=tinyurl_ci" >> $GITHUB_ENV + echo "SPRING_FLYWAY_PASSWORD<> $GITHUB_ENV + echo "$PG_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - name: Build and start stack run: docker compose up -d --build @@ -99,8 +108,12 @@ jobs: RDS_ENDPOINT=$(aws ssm get-parameter \ --name "/tinyurl/cicd/rds-endpoint" \ --query "Parameter.Value" --output text) - echo "EC2_INSTANCE_ID=$EC2_INSTANCE_ID" >> $GITHUB_ENV - echo "RDS_ENDPOINT=$RDS_ENDPOINT" >> $GITHUB_ENV + echo "EC2_INSTANCE_ID<> $GITHUB_ENV + echo "$EC2_INSTANCE_ID" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "RDS_ENDPOINT<> $GITHUB_ENV + echo "$RDS_ENDPOINT" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV - name: Log in to GHCR uses: docker/login-action@v3 From 86476cb693d7622c7c38f1c078d9d933843392f6 Mon Sep 17 00:00:00 2001 From: Buffden Date: Sun, 29 Mar 2026 00:14:00 -0500 Subject: [PATCH 3/3] feat(ci): add automated deploy pipeline with OIDC and SSM RunCommand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add deploy.yml: build → compose smoke → deploy to EC2 via SSM on push to main - Remove push:main trigger from ci-workflows.yml (deploy.yml owns that path now) - Generate ephemeral CI credentials at runtime via openssl rand (no hardcoded passwords) - Fix script injection: move github.sha to env var, never interpolate in run steps - Fix GITHUB_ENV injection: use <> $GITHUB_ENV + echo "POSTGRES_PASSWORD<> $GITHUB_ENV + echo "$PG_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "SPRING_DATASOURCE_USERNAME=tinyurl_appuser_ci" >> $GITHUB_ENV + echo "SPRING_DATASOURCE_PASSWORD<> $GITHUB_ENV + echo "$APP_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "SPRING_FLYWAY_USER=tinyurl_ci" >> $GITHUB_ENV + echo "SPRING_FLYWAY_PASSWORD<> $GITHUB_ENV + echo "$PG_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - name: Validate docker compose configuration run: docker compose config >/dev/null @@ -63,18 +72,27 @@ jobs: runs-on: ubuntu-latest needs: compose-validate - env: - POSTGRES_USER: tinyurl_ci - POSTGRES_PASSWORD: ci_smoke_postgres_pass - SPRING_DATASOURCE_USERNAME: tinyurl_appuser_ci - SPRING_DATASOURCE_PASSWORD: ci_smoke_appuser_pass - SPRING_FLYWAY_USER: tinyurl_ci - SPRING_FLYWAY_PASSWORD: ci_smoke_postgres_pass - steps: - name: Checkout repository uses: actions/checkout@v4 + - name: Generate ephemeral CI credentials + run: | + PG_PASS=$(openssl rand -hex 16) + APP_PASS=$(openssl rand -hex 16) + echo "POSTGRES_USER=tinyurl_ci" >> $GITHUB_ENV + echo "POSTGRES_PASSWORD<> $GITHUB_ENV + echo "$PG_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "SPRING_DATASOURCE_USERNAME=tinyurl_appuser_ci" >> $GITHUB_ENV + echo "SPRING_DATASOURCE_PASSWORD<> $GITHUB_ENV + echo "$APP_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "SPRING_FLYWAY_USER=tinyurl_ci" >> $GITHUB_ENV + echo "SPRING_FLYWAY_PASSWORD<> $GITHUB_ENV + echo "$PG_PASS" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - name: Build and start stack run: docker compose up -d --build