agentic-community / agentic-community/mcp-gateway-registry

feat(terraform): replace Keycloak DB password with RDS IAM authentication

Ouverte
#1,303 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
Python
Étoiles
911
Forks
234
Merge moyen
1 j 11 h
PR mergées (30 j)
62

Description

## Summary

Replace the static Keycloak↔Aurora MySQL password (rotated by Lambda from Secrets Manager) with RDS IAM database authentication via the AWS Advanced JDBC Wrapper. Eliminates static DB credentials for Keycloak entirely; the rotation Lambda remains for DocumentDB.

## Motivation

- Issue #1026 exposed rotation desync as a cause of Keycloak crashes when the password in Secrets Manager drifts from Aurora.
- Static DB passwords + 30-day rotation is more moving parts than IAM auth, which mints short-lived tokens per connection.
- `terraform/aws-ecs/keycloak-database.tf:43` currently suppresses Checkov `CKV_AWS_162` ("RDS cluster has IAM authentication enabled") with the justification that Keycloak uses password auth — this issue removes the suppression.

## Scope

In scope:
- Keycloak ECS task → Aurora MySQL connection in `terraform/aws-ecs/`
- Custom Keycloak Docker image with AWS Advanced JDBC Wrapper

Out of scope (separate issues if needed):
- DocumentDB credentials (DocumentDB does not support IAM auth)
- Registry / mcpgw application secrets
- Helm chart and Docker Compose deployments
- CDK stack in `infra/`

## Plan

### P1 — Custom Keycloak image with AWS JDBC Wrapper

Add the AWS Advanced JDBC Wrapper jar (and MySQL Connector/J as runtime dep) to `/opt/keycloak/providers/` *before* `kc.sh build` so `--optimized` mode bakes the driver in.

Files: `docker/keycloak/Dockerfile`

Pinned versions (bumped via dependabot, not `latest`):
- `aws-advanced-jdbc-wrapper` 2.3.9
- `mysql-connector-j` 8.4.0

```dockerfile
FROM quay.io/keycloak/keycloak:25.0 as builder

ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
ENV KC_FEATURES=token-exchange
ENV KC_DB=mysql
ENV KC_DB_DRIVER=software.amazon.jdbc.Driver

WORKDIR /opt/keycloak

ARG AWS_JDBC_WRAPPER_VERSION=2.3.9
ARG MYSQL_CONNECTOR_VERSION=8.4.0

ADD --chown=keycloak:keycloak \
https://github.com/awslabs/aws-advanced-jdbc-wrapper/releases/download/${AWS_JDBC_WRAPPER_VERSION}/aws-advanced-jdbc-wrapper-${AWS_JDBC_WRAPPER_VERSION}.jar \
/opt/keycloak/providers/

ADD --chown=keycloak:keycloak \
https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/${MYSQL_CONNECTOR_VERSION}/mysql-connector-j-${MYSQL_CONNECTOR_VERSION}.jar \
/opt/keycloak/providers/

RUN keytool -genkeypair -storepass password -storetype PKCS12 -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore conf/server.keystore
RUN /opt/keycloak/bin/kc.sh build

FROM quay.io/keycloak/keycloak:25.0
COPY --from=builder /opt/keycloak/ /opt/keycloak/
WORKDIR /opt/keycloak

HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/health/ready || exit 1

USER keycloak
ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start", "--optimized"]
```

### P2 — Aurora cluster: enable IAM auth

Files: `terraform/aws-ecs/keycloak-database.tf`
- Set `iam_database_authentication_enabled = true`
- Remove the `CKV_AWS_162` skip comment at line 43

### P3 — Bootstrap IAM DB user

One-time SQL run via short-lived ECS task (or maintenance Lambda) using the AWS-managed master credentials:

```sql
CREATE USER 'keycloak_iam' IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS';
GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak_iam';
FLUSH PRIVILEGES;
```

### P4 — ECS task role: grant `rds-db:connect`

Files: `terraform/aws-ecs/keycloak-ecs.tf`

Resource ARN format: `arn:aws:rds-db:::dbuser:/keycloak_iam`

```hcl
resource "aws_iam_role_policy" "keycloak_task_rds_iam_auth" {
name = "keycloak-rds-iam-auth"
role = aws_iam_role.keycloak_task_role.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["rds-db:connect"]
Resource = "arn:aws:rds-db:${var.aws_region}:${data.aws_caller_identity.current.account_id}:dbuser:${aws_rds_cluster.keycloak.cluster_resource_id}/keycloak_iam"
}]
})
}
```

### P5 — Switch ECS task definition

Files: `terraform/aws-ecs/keycloak-ecs.tf` (lines 97-104)
- `KC_DB_URL` → `jdbc:aws-wrapper:mysql:///keycloak?wrapperPlugins=iam&wrapperDialect=aurora-mysql`
- `KC_DB_USERNAME` → `keycloak_iam` (plain env var, no Secrets Manager lookup)
- `KC_DB_DRIVER` → `software.amazon.jdbc.Driver`
- Add `AWS_REGION` env (wrapper needs it for token signing)
- Remove `KC_DB_PASSWORD` entry

### P6 — Delete obsolete infra

Files: `terraform/aws-ecs/{secret-rotation-config.tf, variables.tf, keycloak-database.tf, terraform.tfvars.example, README.md}`
- `aws_secretsmanager_secret.keycloak_db_secret`
- `aws_secretsmanager_secret_rotation.keycloak_db_secret` (secret-rotation-config.tf:35)
- `var.keycloak_database_password` (variables.tf:97)
- Replace `master_password = var.keycloak_database_password` (keycloak-database.tf:54) with `manage_master_user_password = true` (kept as break-glass admin only)
- README references at lines 261, 323
- `terraform.tfvars.example:96`

**Verify**: if only Keycloak used `rotate-rds` Lambda, delete `terraform/aws-ecs/lambda/rotate-rds/` and related resources too. Otherwise keep.

## Risks and mitigations

| Risk | Mitigation |
|------|------------|
| Wrapper bug / outage blocks all DB connections | Keep AWS-managed master user as break-glass; document recovery path |
| 15-min IAM token TTL exhausts on long-lived pool conns | Wrapper refreshes proactively; load-test before merge |
| Driver swap (`KC_DB_DRIVER`) requires full pod replacement | Coordinated cutover, not a rolling deploy |
| Wrapper missing AWS SDK transitive deps on classpath | Add `software.amazon.awssdk:rds` and `:auth` jars only if `NoClassDefFoundError` shows up at runtime |

## Acceptance criteria

- [ ] `docker build docker/keycloak` produces an image with both `aws-advanced-jdbc-wrapper-*.jar` and `mysql-connector-j-*.jar` under `/opt/keycloak/providers/`
- [ ] `terraform apply` succeeds with `iam_database_authentication_enabled = true` and no `CKV_AWS_162` skip
- [ ] Keycloak ECS task starts, reaches `/health/ready`, persists realms across task replacement
- [ ] `aws secretsmanager list-secrets` no longer returns `keycloak_db_secret`
- [ ] Keycloak survives a forced 20-minute idle period without connection errors (token-refresh smoke test)
- [ ] Checkov scan in CI passes without the `CKV_AWS_162` suppression

## Out of scope / follow-ups

- Mirror the change in `infra/` (CDK) — file separately
- Helm chart equivalent using IRSA — file separately if requested
- Apply same pattern to any future RDS-backed services

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.