Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
node_modules
.DS_Store
release
docker/.env
jdbc/lib/classes
jdbc/lib/ojdbc11.jar
jdbc/lib/json.jar
jdbc/lib/kerberos-jdbc-bridge.jar
20 changes: 20 additions & 0 deletions docker/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copy to .env and adjust before: docker compose --env-file .env up -d
#
# Oracle Database Free (container-registry.oracle.com/database/free:latest)
ORACLE_PWD=change_me_oracle_system_password

# MIT Kerberos realm (must stay uppercase in krb5.conf)
KRB5_REALM=HACKOLADE.LOCAL
KRB5_DOMAIN=hackolade.local

# Hostnames used in service principals (must match /etc/hosts on Mac/Azure client)
ORACLE_FQDN=oracle-db.hackolade.local
KDC_FQDN=kdc.hackolade.local

# Kerberos end-user for Hackolade plugin testing (auth method: Kerberos)
KRB_USER=hackolade_krb
KRB_USER_PASSWORD=change_me_krb_user_password

# KDC master password (kdb5_util) and kadmin/admin principal password
KDC_MASTER_PASSWORD=change_me_kdc_master
KADMIN_PASSWORD=change_me_kadmin
28 changes: 28 additions & 0 deletions docker/KERBEROS-PLATFORMS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Kerberos platform notes

## Hackolade plugin

Kerberos uses **JDBC Thin + Java 11–21**, not Oracle Instant Client or thick mode.

Works on **macOS, Linux, and Windows** with:

- MIT Kerberos (`brew install krb5` on Mac)
- Valid ticket (`docker/scripts/mac-kinit.sh` for the local lab)
- Java 21 recommended (`brew install openjdk@21`)

Test from the plugin repo:

```bash
npm install
node docker/scripts/test-jdbc-kerberos.js
```

See [../docs/KERBEROS-JDBC.md](../docs/KERBEROS-JDBC.md).

## macOS + Instant Client (password / OS auth only)

Instant Client on macOS does **not** support database Kerberos (`ORA-12638`). Use JDBC Kerberos in Hackolade, or use **username/password + thick** for non-Kerberos work on Mac.

## Docker lab

The KDC and Oracle server in `docker/` are platform-agnostic. Only the Hackolade host needs `kinit` + Java for Kerberos connections.
182 changes: 182 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Oracle Free + Kerberos local lab

> **Hackolade Kerberos:** JDBC Thin + Java 11–21 (no Instant Client). See [KERBEROS-PLATFORMS.md](./KERBEROS-PLATFORMS.md) and [../docs/KERBEROS-JDBC.md](../docs/KERBEROS-JDBC.md).

Docker lab for testing the Hackolade Oracle plugin with **Kerberos (JDBC)** and optional **thick password** auth, using the official image you already pulled:

`container-registry.oracle.com/database/free:latest`

The same `docker-compose.yml` runs on **macOS (M4)** and can be copied to an **Azure Linux VM** with minimal changes.

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│ Mac / Azure VM (Hackolade host) │
│ • Java 11–21 + npm install (JDBC Kerberos artifacts) │
│ • krb5.conf + kinit → TGT (MIT krb5) │
└───────────────────────────┬─────────────────────────────────┘
│ :1521 / :88
┌───────────────────────────▼─────────────────────────────────┐
│ Docker network (kerbnet) │
│ ┌──────────────┐ ┌────────────────────────────────────┐ │
│ │ MIT KDC │ │ Oracle Database Free │ │
│ │ kdc.hackolade│ │ oracle-db.hackolade.local │ │
│ │ .local │ │ SPN: oracle/oracle-db...@REALM │ │
│ └──────────────┘ │ keytab + sqlnet.ora (server only) │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```

**Important:** Hackolade does not run inside Docker. Only the database and KDC do. Kerberos tickets and Java live on the Hackolade host.

## Prerequisites

- Docker Desktop (Mac M4) or Docker Engine (Azure VM)
- Logged in to Oracle Container Registry:
`docker login container-registry.oracle.com`
- Image already pulled: `database/free:latest`
- For Kerberos: **Java 21** (`brew install openjdk@21 krb5`) — no Instant Client
- For password + thick on Mac: [Instant Client for macOS ARM64](https://www.oracle.com/database/technologies/instant-client/macos-arm64-downloads.html) (optional)

### About `database/adb-free`

`adb-free` is Autonomous Database Free (wallet/TLS, different ports). This lab targets **`database/free`** (listener on 1521, `FREEPDB1`). Use adb-free only if you extend the compose file yourself.

## Quick start

```bash
cd docker
cp .env.example .env
chmod +x scripts/*.sh kdc/entrypoint.sh kerberos-setup/setup.sh oracle/scripts/startup/*.sh

./scripts/bootstrap.sh
```

First Oracle startup often takes **10–15 minutes**. Bootstrap waits for Oracle health, then runs `./scripts/fix-kerberos-principals.sh` (uses `kadmin.local` inside the KDC — reliable for `ktadd`).

If Oracle exits with code **137**, increase Docker Desktop memory (4–6 GB minimum).

### Host name resolution

Add to `/etc/hosts` on the machine running Hackolade:

```
127.0.0.1 oracle-db.hackolade.local kdc.hackolade.local
```

See `scripts/hosts-snippet.txt`.

### macOS client (Kerberos via JDBC — recommended)

1. **Java 21** (JDK 25 breaks Oracle Kerberos in JDBC):
```bash
brew install openjdk@21 krb5
```
2. Build the JDBC bridge and obtain a ticket:
```bash
cd docker && ./scripts/mac-kinit.sh
cd .. && npm run build:jdbc
./docker/scripts/ensure-kerberos-db-user.sh # if DB existed before Kerberos setup
node docker/scripts/test-jdbc-kerberos.js # expect: SUCCESS: [ [ 1 ] ]
```
3. Package the plugin and point Hackolade at it:
```bash
npm ci && npm run package
# copy release to ~/.hackolade/plugins/Oracle (or your pluginPath)
```
4. Hackolade connection:

| Field | Value |
|--------|--------|
| Auth | Kerberos |
| Java path | `/opt/homebrew/opt/openjdk@21/bin/java` |
| Host | `oracle-db.hackolade.local` |
| Port | `1521` |
| Service | `FREEPDB1` |
| User | `hackolade_krb` (or empty for ticket-only mapping) |
| Ticket cache | default `~/.hackolade/krb5cc_hackolade` |

No Instant Client is required for Kerberos when using JDBC.

### Smoke tests

```bash
# Password (no Kerberos) — from host
./scripts/smoke-password.sh

# Kerberos JDBC (cross-platform, no Instant Client)
cd .. # Oracle plugin repo root
npm run build:jdbc
node docker/scripts/test-jdbc-kerberos.js
```

Instant Client **Basic Light** does not include SQL*Plus. To add it, download the separate **SQL*Plus** package for macOS ARM64 from Oracle and unzip into the same `instantclient_*` folder.

## Manual steps (if you prefer)

```bash
docker compose up -d
./scripts/fix-kerberos-principals.sh
```

The `kerberos-setup` compose profile uses remote `kadmin` and may fail on `ktadd`; prefer `fix-kerberos-principals.sh`.

## Reset lab

```bash
docker compose down -v # removes DB + KDC + Kerberos volume data
```

## Port to Azure VM

1. Create an Ubuntu 22.04+ VM (or RHEL). **4 GB+ RAM** recommended for Oracle Free.
2. Install Docker and compose plugin; login to `container-registry.oracle.com`.
3. Copy the entire `docker/` directory to the VM.
4. Open NSG / firewall: **1521** (Oracle), **88** tcp/udp (Kerberos, if clients connect from outside the VM).
5. In `.env`, you can keep the same `ORACLE_FQDN` / `KDC_FQDN` if clients use VM public IP in `/etc/hosts`:

```
<VM_PUBLIC_IP> oracle-db.hackolade.local kdc.hackolade.local
```

6. Run `./scripts/bootstrap.sh` on the VM.
7. Run Hackolade on your Mac or a jump box with `/etc/hosts` pointing at the VM IP, **Java 21**, and `kinit` (port 88 to the KDC if remote).

## Troubleshooting

| Symptom | Check |
|--------|--------|
| Oracle container unhealthy / OOM | Increase Docker memory (4 GB+); try `free:latest-lite` if memory protection key errors (see [oracle/docker-images#2972](https://github.com/oracle/docker-images/issues/2972)) |
| `kinit: CLIENT_NOT_FOUND` | Run `./scripts/fix-kerberos-principals.sh` |
| `kinit: Password incorrect` | Run `./scripts/reset-krb-password.sh` then use exact `KRB_USER_PASSWORD` from `.env` (watch `!` in zsh) |
| `ktadd` / `change-password` privilege / missing `v5srvtab` | Do **not** use `kerberos-setup` profile — run `./scripts/fix-kerberos-principals.sh` |
| Oracle exit **137** during bootstrap | Docker OOM — allocate more RAM to Docker Desktop |
| `ORA-01017` (Kerberos JDBC) | Run `./scripts/ensure-kerberos-db-user.sh` — external user may be missing in FREEPDB1 |
| `ORA-12655` | Server: run `./scripts/fix-kerberos-principals.sh`; client: `klist` and `./scripts/mac-kinit.sh` |
| `ORA-28040` / auth failure | `klist` — re-`kinit`; ticket expired |
| SPN / hostname mismatch | Host in connect string must match `oracle/${ORACLE_FQDN}@REALM` — use FQDN, not `localhost` |
| Thick `DPI-1047` on M4 | Use **ARM64** Instant Client, not x86 |
| Kerberos not applied in DB | Re-run setup + restart: `docker compose --profile setup run --rm kerberos-setup && docker compose restart oracle` |
| User missing in PDB | `./scripts/ensure-kerberos-db-user.sh` |

## Files

| Path | Role |
|------|------|
| `docker-compose.yml` | KDC + Oracle Free + optional setup job |
| `kdc/` | MIT KDC image |
| `kerberos-setup/` | Principals + keytab + server `sqlnet.ora` |
| `oracle/scripts/setup/` | `EXTERNALLY` Oracle user (first DB init) |
| `oracle/scripts/startup/` | Apply Kerberos config each start |
| `client/macos/` | Host `krb5.conf` template |

## Default principals

| Principal | Purpose |
|-----------|---------|
| `oracle/oracle-db.hackolade.local@HACKOLADE.LOCAL` | Database service (keytab) |
| `hackolade_krb@HACKOLADE.LOCAL` | Hackolade end user (`kinit`) |
| `admin/admin@HACKOLADE.LOCAL` | kadmin (setup only) |

Oracle DB user: `hackolade_krb` identified as `hackolade_krb@HACKOLADE.LOCAL` in `FREEPDB1`.
12 changes: 12 additions & 0 deletions docker/client/hackolade-connection.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"comment": "Example Hackolade Oracle connection for Kerberos JDBC (local Docker lab)",
"name": "Oracle Free Kerberos (local Docker)",
"connectionMethod": "Basic",
"host": "oracle-db.hackolade.local",
"port": 1521,
"identifierType": "serviceName",
"serviceName": "FREEPDB1",
"authMethod": "Kerberos",
"javaPath": "/opt/homebrew/opt/openjdk@21/bin/java",
"userName": "hackolade_krb"
}
22 changes: 22 additions & 0 deletions docker/client/macos/krb5.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Install as /etc/krb5.conf or set KRB5_CONFIG to this file before kinit.
# Points at the KDC exposed on localhost (Docker port mapping).

[libdefaults]
default_realm = HACKOLADE.LOCAL
dns_lookup_realm = false
dns_lookup_kdc = false
rdns = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true

[realms]
HACKOLADE.LOCAL = {
kdc = kdc.hackolade.local:88
admin_server = kdc.hackolade.local:749
default_domain = hackolade.local
}

[domain_realm]
.hackolade.local = HACKOLADE.LOCAL
hackolade.local = HACKOLADE.LOCAL
107 changes: 107 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Local Oracle Free + MIT Kerberos lab for Hackolade plugin testing (Kerberos JDBC).
# Same layout can run on an Azure VM (Linux) with the same images and .env.
#
# Usage:
# cp .env.example .env
# docker compose up -d
# docker compose --profile setup run --rm kerberos-setup
# See README.md for Mac client (/etc/hosts, kinit, Instant Client).

services:
kdc:
build:
context: ./kdc
dockerfile: Dockerfile
container_name: hackolade-kdc
hostname: kdc.hackolade.local
environment:
KRB5_REALM: ${KRB5_REALM:-HACKOLADE.LOCAL}
KDC_MASTER_PASSWORD: ${KDC_MASTER_PASSWORD}
KADMIN_PASSWORD: ${KADMIN_PASSWORD}
volumes:
- kdc-data:/var/kerberos/krb5kdc
- ./krb5/krb5.conf:/etc/krb5.conf:ro
- ./krb5/kdc.conf:/etc/krb5kdc/kdc.conf:ro
- ./krb5/kadm5.acl:/etc/krb5kdc/kadm5.acl:ro
ports:
- "88:88/tcp"
- "88:88/udp"
- "749:749/tcp"
networks:
kerbnet:
aliases:
- kdc.hackolade.local
healthcheck:
test: ["CMD-SHELL", "kadmin.local -q 'list_principals' 2>/dev/null | grep -q admin"]
interval: 5s
timeout: 5s
retries: 30
start_period: 15s

oracle:
image: container-registry.oracle.com/database/free:latest
container_name: hackolade-oracle-free
hostname: oracle-db.hackolade.local
depends_on:
kdc:
condition: service_healthy
environment:
ORACLE_PWD: ${ORACLE_PWD}
shm_size: "2gb"
volumes:
- oracle-data:/opt/oracle/oradata
- kerberos-config:/opt/oracle/kerberos
- ./krb5/krb5.conf:/etc/krb5.conf:ro
- ./oracle/scripts/setup:/opt/oracle/scripts/setup:ro
- ./oracle/scripts/startup:/opt/oracle/scripts/startup:ro
ports:
- "1521:1521"
networks:
kerbnet:
aliases:
- oracle-db.hackolade.local
healthcheck:
test:
[
"CMD-SHELL",
"echo \"SELECT 1 FROM DUAL;\" | sqlplus -s -L system/\"$$ORACLE_PWD\"@//localhost:1521/FREEPDB1 | grep -q 1",
]
interval: 30s
timeout: 15s
retries: 20
start_period: 600s

# One-shot: create Kerberos principals + keytab, then signal Oracle startup scripts.
# Run after oracle is healthy: docker compose --profile setup run --rm kerberos-setup
kerberos-setup:
profiles: ["setup"]
build:
context: ./kerberos-setup
dockerfile: Dockerfile
container_name: hackolade-kerberos-setup
environment:
KRB5_REALM: ${KRB5_REALM:-HACKOLADE.LOCAL}
ORACLE_FQDN: ${ORACLE_FQDN:-oracle-db.hackolade.local}
KRB_USER: ${KRB_USER:-hackolade_krb}
KRB_USER_PASSWORD: ${KRB_USER_PASSWORD}
KADMIN_PASSWORD: ${KADMIN_PASSWORD}
volumes:
- kerberos-config:/kerberos
- ./krb5/krb5.conf:/etc/krb5.conf:ro
- ./oracle/config/sqlnet.ora.template:/templates/sqlnet.ora.template:ro
depends_on:
kdc:
condition: service_healthy
oracle:
condition: service_healthy
networks:
- kerbnet

volumes:
kdc-data:
oracle-data:
kerberos-config:

networks:
kerbnet:
driver: bridge
10 changes: 10 additions & 0 deletions docker/kdc/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM rockylinux:9

RUN dnf install -y krb5-server krb5-workstation && dnf clean all

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 88/tcp 88/udp 749/tcp

ENTRYPOINT ["/entrypoint.sh"]
Loading