Skip to content

Commit e1ec6a9

Browse files
committed
feat: adding sshopk config
1 parent b3eca80 commit e1ec6a9

File tree

6 files changed

+370
-0
lines changed

6 files changed

+370
-0
lines changed

Dockerfile.ssh-server

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
FROM ubuntu:24.04
2+
3+
RUN apt-get update && apt-get install -y \
4+
openssh-server \
5+
wget \
6+
curl \
7+
ca-certificates \
8+
&& rm -rf /var/lib/apt/lists/*
9+
10+
RUN wget -qO /usr/local/bin/opkssh https://github.com/openpubkey/opkssh/releases/latest/download/opkssh-linux-amd64 && \
11+
chmod +x /usr/local/bin/opkssh
12+
13+
RUN groupadd --system opksshuser && \
14+
useradd -r -M -s /sbin/nologin -g opksshuser opksshuser
15+
16+
RUN useradd -m -s /bin/bash testuser && \
17+
echo 'testuser:password' | chpasswd
18+
19+
RUN mkdir /var/run/sshd && \
20+
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
21+
echo "AuthorizedKeysCommand /usr/local/bin/opkssh verify %u %k %t" >> /etc/ssh/sshd_config && \
22+
echo "AuthorizedKeysCommandUser opksshuser" >> /etc/ssh/sshd_config
23+
24+
RUN mkdir -p /etc/opk /home/testuser/.opk && \
25+
chown testuser:testuser /home/testuser/.opk && \
26+
chmod 700 /home/testuser/.opk
27+
28+
EXPOSE 2222
29+
30+
CMD ["/usr/sbin/sshd", "-D", "-p", "2222"]

TESTING-OPKSSH.md

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# Testing opkssh with Keycloak
2+
3+
This guide shows you how to test SSH authentication using OpenID Connect (OIDC) via Keycloak.
4+
5+
## What is opkssh?
6+
7+
opkssh enables SSH authentication using OpenID Connect identities (like `test@test.com`) instead of traditional SSH keys. Your OIDC identity token is embedded in a temporary SSH certificate that expires after 24 hours.
8+
9+
## Architecture
10+
11+
```
12+
[Your Machine] [Docker Stack]
13+
| |
14+
| 1. opkssh login |
15+
|-------------------------------->| Keycloak (OIDC Provider)
16+
| 2. Browser opens |
17+
| 3. Login with test@test.com |
18+
|<--------------------------------|
19+
| 4. SSH key generated |
20+
| |
21+
| 5. ssh -p 2222 testuser@localhost
22+
|-------------------------------->| SSH Server (verifies via opkssh)
23+
| 6. Logged in! |
24+
```
25+
26+
## Prerequisites
27+
28+
### 1. Install opkssh on Your Local Machine
29+
30+
**macOS:**
31+
```bash
32+
brew tap openpubkey/opkssh
33+
brew install opkssh
34+
```
35+
36+
**Linux:**
37+
```bash
38+
curl -L https://github.com/openpubkey/opkssh/releases/latest/download/opkssh-linux-amd64 -o opkssh
39+
chmod +x opkssh
40+
sudo mv opkssh /usr/local/bin/
41+
```
42+
43+
**Windows:**
44+
```powershell
45+
curl https://github.com/openpubkey/opkssh/releases/latest/download/opkssh-windows-amd64.exe -o opkssh.exe
46+
# Add to PATH or use ./opkssh.exe
47+
```
48+
49+
### 2. Start the Docker Stack
50+
51+
```bash
52+
docker-compose up -d
53+
```
54+
55+
Wait for services to be healthy:
56+
```bash
57+
docker-compose ps
58+
```
59+
60+
## Testing Steps
61+
62+
### Step 1: Login with opkssh
63+
64+
Run this command to authenticate with Keycloak:
65+
66+
```bash
67+
opkssh login --provider="http://localhost:8082/realms/minio_realm,opkssh-client"
68+
```
69+
70+
**What happens:**
71+
1. Your browser opens to Keycloak login page
72+
2. Login with:
73+
- **Username:** `testuser`
74+
- **Password:** `password`
75+
3. opkssh generates an SSH certificate at `~/.ssh/id_ecdsa`
76+
4. The certificate contains your OIDC identity token from Keycloak
77+
78+
### Step 2: SSH to the Test Server
79+
80+
Now SSH using your OIDC identity:
81+
82+
```bash
83+
ssh -p 2222 testuser@localhost
84+
```
85+
86+
**You should be logged in without entering a password!**
87+
88+
The SSH server verified your identity by:
89+
1. Receiving your SSH certificate
90+
2. Extracting the OIDC token from it
91+
3. Verifying the token against Keycloak
92+
4. Checking `/etc/opk/auth_id` to confirm `test@test.com` can login as `testuser`
93+
94+
### Step 3: Verify You're Logged In
95+
96+
Inside the SSH session:
97+
98+
```bash
99+
whoami
100+
# Output: testuser
101+
102+
hostname
103+
# Output: (container hostname)
104+
105+
exit
106+
```
107+
108+
### Step 4: Inspect Your SSH Certificate
109+
110+
On your local machine:
111+
112+
```bash
113+
# View the SSH certificate
114+
cat ~/.ssh/id_ecdsa-cert.pub
115+
116+
# View certificate details
117+
ssh-keygen -L -f ~/.ssh/id_ecdsa-cert.pub
118+
```
119+
120+
You'll see:
121+
- **Valid:** Current time to expiration (24h from login)
122+
- **Principals:** testuser
123+
- **Extensions:** Contains your OIDC identity token
124+
125+
## Configuration Details
126+
127+
### Keycloak Configuration
128+
129+
- **Realm:** `minio_realm`
130+
- **Client ID:** `opkssh-client`
131+
- **Client Type:** Public (no client secret needed)
132+
- **Redirect URIs:** `http://localhost:3000/login-callback` (and 10001, 11110)
133+
134+
### SSH Server Configuration
135+
136+
**Provider Configuration (`/etc/opk/providers`):**
137+
```
138+
http://coraza-waf:8082/realms/minio_realm opkssh-client 24h
139+
```
140+
141+
**Authorization Configuration (`/etc/opk/auth_id`):**
142+
```
143+
testuser test@test.com http://coraza-waf:8082/realms/minio_realm
144+
```
145+
146+
This allows the OIDC identity `test@test.com` to SSH as the Linux user `testuser`.
147+
148+
## Troubleshooting
149+
150+
### SSH Connection Refused
151+
152+
Check if the SSH server is running:
153+
```bash
154+
docker ps | grep ssh-test-server
155+
docker logs ssh-test-server
156+
```
157+
158+
### Authentication Failed
159+
160+
1. **Check your SSH certificate:**
161+
```bash
162+
ls -la ~/.ssh/id_ecdsa*
163+
```
164+
You should see:
165+
- `id_ecdsa` (private key)
166+
- `id_ecdsa.pub` (public key)
167+
- `id_ecdsa-cert.pub` (certificate)
168+
169+
2. **Verify certificate is valid:**
170+
```bash
171+
ssh-keygen -L -f ~/.ssh/id_ecdsa-cert.pub
172+
```
173+
Check that "Valid:" shows it hasn't expired.
174+
175+
3. **Re-login if expired:**
176+
```bash
177+
opkssh login --provider="http://localhost:8082/realms/minio_realm,opkssh-client"
178+
```
179+
180+
### Verify opkssh on Server
181+
182+
Check if the SSH server can verify your certificate:
183+
184+
```bash
185+
# Copy your public key
186+
cat ~/.ssh/id_ecdsa-cert.pub
187+
188+
# Test verification (replace <PUBKEY> with actual key)
189+
docker exec ssh-test-server /usr/local/bin/opkssh verify testuser "<PUBKEY>" ssh-ed25519
190+
```
191+
192+
### Check Keycloak Connectivity
193+
194+
Verify the SSH server can reach Keycloak:
195+
196+
```bash
197+
docker exec ssh-test-server curl http://coraza-waf:8082/realms/minio_realm/.well-known/openid-configuration
198+
```
199+
200+
Should return JSON with OIDC configuration.
201+
202+
### Enable SSH Debug Mode
203+
204+
For detailed SSH logs:
205+
206+
```bash
207+
ssh -v -p 2222 testuser@localhost
208+
```
209+
210+
Use `-vv` or `-vvv` for even more detail.
211+
212+
## Advanced: Adding More Users
213+
214+
### Add Another Keycloak User
215+
216+
1. **Access Keycloak Admin Console:**
217+
- URL: http://localhost:8082
218+
- Username: `admin`
219+
- Password: `admin`
220+
221+
2. **Go to:** Users → Add User
222+
- Username: `alice`
223+
- Email: `alice@example.com`
224+
- First Name: `Alice`
225+
- Save
226+
227+
3. **Set Password:** Credentials → Set Password
228+
229+
### Authorize the New User for SSH
230+
231+
Edit `opk-auth_id`:
232+
```bash
233+
echo "testuser alice@example.com http://coraza-waf:8082/realms/minio_realm" >> opk-auth_id
234+
```
235+
236+
Restart SSH server:
237+
```bash
238+
docker-compose restart ssh-server
239+
```
240+
241+
Now Alice can SSH after running:
242+
```bash
243+
opkssh login --provider="http://localhost:8082/realms/minio_realm,opkssh-client"
244+
ssh -p 2222 testuser@localhost
245+
```
246+
247+
## Advanced: Group-Based Access
248+
249+
### Add Groups to Keycloak
250+
251+
1. **Create Group:** Groups → New → Name: `ssh-users`
252+
2. **Add to Client Scope:**
253+
- Client Scopes → Create → Name: `groups`
254+
- Mappers → Add Mapper → Group Membership
255+
- Token Claim Name: `groups`
256+
3. **Add to Client:** Clients → opkssh-client → Client Scopes → Add client scope → `groups`
257+
258+
### Update Authorization
259+
260+
Edit `opk-auth_id`:
261+
```bash
262+
echo 'testuser oidc:groups:ssh-users http://coraza-waf:8082/realms/minio_realm' >> opk-auth_id
263+
```
264+
265+
Now any user in the `ssh-users` group can SSH as `testuser`.
266+
267+
## Security Notes
268+
269+
1. **SSH certificates expire after 24h** - Users must run `opkssh login` daily
270+
2. **No long-lived SSH keys** - Reduces risk if a machine is compromised
271+
3. **Centralized access control** - Manage SSH access via Keycloak instead of distributing SSH keys
272+
4. **Audit trail** - Keycloak logs all authentication events
273+
274+
## Cleanup
275+
276+
Stop and remove all containers:
277+
```bash
278+
docker-compose down
279+
```
280+
281+
Remove your SSH certificate:
282+
```bash
283+
rm ~/.ssh/id_ecdsa*
284+
```
285+
286+
## Next Steps
287+
288+
- Deploy to production servers (see [scripts/installing.md](scripts/installing.md))
289+
- Integrate with your existing OIDC provider (Azure AD, Google, etc.)
290+
- Configure more complex policies (see [docs/policyplugins.md](docs/policyplugins.md))
291+
- Set up group-based access control
292+
- Configure certificate expiration policies
293+
294+
## Resources
295+
296+
- [opkssh GitHub](https://github.com/openpubkey/opkssh)
297+
- [OpenPubkey Documentation](https://github.com/openpubkey/openpubkey)
298+
- [Keycloak Documentation](https://www.keycloak.org/documentation)

docker-compose.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,22 @@ services:
8181
networks:
8282
- minio-net
8383

84+
ssh-server:
85+
build:
86+
context: .
87+
dockerfile: Dockerfile.ssh-server
88+
container_name: ssh-test-server
89+
ports:
90+
- "2222:2222"
91+
volumes:
92+
- ./opk-providers:/etc/opk/providers:ro
93+
- ./opk-auth_id:/etc/opk/auth_id:ro
94+
depends_on:
95+
- keycloak
96+
- coraza-waf
97+
networks:
98+
- minio-net
99+
84100
volumes:
85101
minio-data:
86102
postgres_data:

keycloak-minio-docker/minio-realm-config.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,28 @@
7777
}
7878
}
7979
]
80+
},
81+
{
82+
"clientId": "opkssh-client",
83+
"name": "OpenPubkey SSH Client",
84+
"enabled": true,
85+
"protocol": "openid-connect",
86+
"publicClient": true,
87+
"directAccessGrantsEnabled": false,
88+
"standardFlowEnabled": true,
89+
"redirectUris": [
90+
"http://localhost:3000/login-callback",
91+
"http://localhost:10001/login-callback",
92+
"http://localhost:11110/login-callback"
93+
],
94+
"webOrigins": [
95+
"+"
96+
],
97+
"defaultClientScopes": [
98+
"openid",
99+
"profile",
100+
"email"
101+
]
80102
}
81103
],
82104
"roles": {

opk-auth_id

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# principal email/sub issuer
2+
testuser test@test.com http://coraza-waf:8082/realms/minio_realm

opk-providers

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Issuer Client-ID expiration-policy
2+
http://coraza-waf:8082/realms/minio_realm opkssh-client 24h

0 commit comments

Comments
 (0)