# RDS for Db2 — Self-Managed Active Directory + Kerberos Join an RDS for Db2 instance directly to a customer-managed Active Directory domain for Kerberos single sign-on — no Amazon Managed Microsoft AD and no directory trust in the path. ## Source - Workspace: `04-db2-client/self-managed-ad-for-rds-db2/` (`README.md`, `README-UI.md`, `README-PowerShell.md`, `README-KMS-Secret.md`, `README-RDS-Db2.md`, `README-Networking.md`, `README-Db2-Client.md`, `README-Blog.md`) - Bundled scripts: `scripts/Db2KerberosConnection.java`, `scripts/db2-kerberos-test.sh` - Blog: self-managed AD Kerberos for RDS for Db2 (`aws-samples/sample-rds-db2-tools`) - AWS doc: ## Architecture RDS for Db2 joins your AD directly. A dedicated service account, scoped to one OU, is stored in Secrets Manager and encrypted with a customer-managed KMS key. During join, RDS reads the secret to register the instance. A domain-joined client gets a Kerberos ticket (TGT) from the AD KDC and connects with no password exchanged. ## 1. Delegate the nine AD permissions Create a dedicated OU and service account, then grant the exact permissions on **descendant User objects** (RDS provisions principals as User objects): - Create / Delete User and Computer objects in the OU - Reset Password (extended right) - Read + Write `msDS-SupportedEncryptionTypes` - Read + Write `servicePrincipalName` **Gotcha:** the ADUC Delegation of Control Wizard filters `servicePrincipalName` (and `msDS-SupportedEncryptionTypes`) out of the User-object attribute list. Grant those with **ADSI Edit** (`adsiedit.msc`), not ADUC — the most common failure, producing an ACL that looks correct but fails the join at runtime. Scope to User objects, not Computer objects. The PowerShell helper `Grant-ADDomainJoinPrivileges.ps1` applies all permissions in one idempotent pass; verify with `Show-OUDelegation.ps1`. ## 2. KMS key + Secrets Manager secret Create a dedicated symmetric KMS key (not the AWS default) in the same account/Region. Store two keys in the secret: - `SELF_MANAGED_ACTIVE_DIRECTORY_USERNAME` — sAMAccountName **only** (e.g. `rdsdb2svc`); a `DOMAIN\` prefix fails instance creation - `SELF_MANAGED_ACTIVE_DIRECTORY_PASSWORD` Attach a resource policy trusting `rds.amazonaws.com`, guarded against the confused-deputy problem with `aws:SourceArn` / `aws:SourceAccount`: ```json { "Effect": "Allow", "Principal": { "Service": "rds.amazonaws.com" }, "Action": "secretsmanager:GetSecretValue", "Resource": "*", "Condition": { "StringEquals": { "aws:SourceAccount": "" }, "ArnLike": { "aws:SourceArn": "arn:aws:rds:::db:*" } } } ``` ## 3. Join the instance ```bash aws rds modify-db-instance \ --db-instance-identifier "" \ --domain-fqdn "" \ --domain-ou "OU=RDSDb2,DC=company,DC=com" \ --domain-auth-secret-arn "" \ --domain-dns-ips "" "" \ --apply-immediately ``` Then reboot for the join to take effect. Supply at least two `--domain-dns-ips` for redundancy. New instances take the same four flags plus `--storage-encrypted --kms-key-id`. **Verify:** ```bash aws rds describe-db-instances --db-instance-identifier "" \ --query 'DBInstances[0].{Status:DBInstanceStatus,Domain:DomainMemberships}' ``` A successful join shows `DomainMemberships` with `Status: joined`. ## 4. Networking (port matrix) Open between RDS and the domain controllers (and from the client): | Protocol | Port(s) | Service | |---|---|---| | TCP+UDP | 53 | DNS | | TCP+UDP | 88 | Kerberos | | TCP+UDP | 389 / TCP 3268 | LDAP / Global Catalog | | TCP+UDP | 464 | Kerberos password change | | TCP+UDP | 49152–65535 | RPC dynamic ports | Missing the RPC range is the top cause of intermittent failures after a working initial join. Keep clock skew **under 5 minutes** (shared NTP) and ensure VPC DNS resolves the AD domain. Topologies: same VPC (reference by SG ID), cross-account (VPC Peering / Transit Gateway + CIDR rules + Route 53 Resolver), or Azure-hosted DCs (Site-to-Site VPN / Direct Connect + ExpressRoute). ## 5. Domain-join the client + connect On an AL2023 EC2 client in the same VPC, install `realmd`/`sssd`/`adcli`/`krb5-workstation`, join the realm, then install the Db2 Runtime Client (`db2-driver.sh`) and configure DSNs (`db2client-configure.sh` auto-detects the realm and writes both local-auth and Kerberos DSNs): ```bash kinit your.username@COMPANY.COM # obtain a TGT klist # confirm ticket present db2 "connect to RDSAKS" # SSL + Kerberos DSN, no password ``` The RDS admin account (created with `--master-username admin`, preferably with `--manage-master-user-password`) is a **local** account — it cannot get a Kerberos ticket and is used only for local-auth DSNs. AD users need a ticket plus `GRANT CONNECT ON DATABASE TO USER domain\user`. DSN matrix written by the configure script: `RDSAT` (TCP/local), `RDSAS` (SSL/local), `RDSAKS` (SSL/Kerberos), and per-database `T` / `S` / `SK`. Which are written depends on the `db2comm` parameter (`TCPIP`, `SSL`, or both). ## 6. JDBC Kerberos The bundled `scripts/Db2KerberosConnection.java` (driven by `scripts/db2-kerberos-test.sh`) connects with the IBM JDBC driver (`db2jcc4.jar` v4.33+) using: ```java props.setProperty("securityMechanism", "11"); // 11 = Kerberos props.setProperty("sslConnection", "true"); props.setProperty("sslVersion", "TLSv1.2"); props.setProperty("sslCertLocation", "/path/to/-bundle.pem"); ``` `securityMechanism=11` selects Kerberos (no user/password). For SSL use the **region-specific** PEM via `sslCertLocation` — never `global-bundle.pem`, which the IBM driver does not support. Download it: ```bash curl -sL https://truststore.pki.rds.amazonaws.com//-bundle.pem \ -o -bundle.pem ``` ## Must-surface facts - Self-managed AD path uses `--domain-fqdn`, `--domain-ou`, `--domain-auth-secret-arn`, `--domain-dns-ips` — no Managed AD or trust required. - Secret keys are `SELF_MANAGED_ACTIVE_DIRECTORY_USERNAME` (sAMAccountName only) and `_PASSWORD`; resource policy carries `aws:SourceArn` / `aws:SourceAccount`. - Grant `servicePrincipalName` via ADSI Edit, not ADUC. - Open RPC 49152–65535; keep clock skew under 5 minutes. - Verify with `DomainMemberships: joined`; JDBC uses `securityMechanism=11` + region PEM via `sslCertLocation`.