ssh-auth-cmd 0.1.0

SSH AuthorizedKeysCommand multiplexer - chain multiple SSH authentication sources
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# ssh-auth-cmd Configuration and Setup

## Overview

`ssh-auth-cmd` is a Rust application designed to chain multiple SSH `AuthorizedKeysCommand` configurations, since OpenSSH only supports configuring a single one. The new version supports individual configuration files, user switching, comprehensive OpenSSH placeholder support, and automatic installation.

## Installation

1. Build the application:
```bash
cargo build --release
```

2. Install the binary:
```bash
sudo cp target/release/ssh-auth-cmd /usr/local/bin/
sudo chmod +x /usr/local/bin/ssh-auth-cmd
```

3. Install using the built-in installer (recommended):
```bash
sudo /usr/local/bin/ssh-auth-cmd install
```

Or with a specific user:
```bash
sudo /usr/local/bin/ssh-auth-cmd install --user nobody
```

## Configuration Directory Structure

Commands are now configured in individual TOML files in `/etc/ssh/auth_cmd.d/`:

```
/etc/ssh/auth_cmd.d/
├── 01-local-keys.toml
├── 02-ldap-keys.toml
├── 03-database-keys.toml
└── 99-emergency-keys.toml
```

Files are processed in alphabetical order, so you can use prefixes to control execution order.

## Configuration File Format

Each configuration file contains a single command definition:

### Example: `/etc/ssh/auth_cmd.d/01-local-keys.toml`
```toml
name = "local_keys"
command = "cat"
args = ["/home/%u/.ssh/authorized_keys"]
enabled = true
timeout = 30
user = "nobody"
readonly = false
```

### Example: `/etc/ssh/auth_cmd.d/02-ldap-keys.toml`
```toml
name = "ldap_keys"
command = "/usr/local/bin/ldap-ssh-keys"
args = ["--user", "%u", "--hostname", "%h", "--connection", "%C"]
enabled = true
timeout = 60
user = "ldap-user"
readonly = false
```

### Example: `/etc/ssh/auth_cmd.d/03-audit-only.toml`
```toml
name = "audit_logger"
command = "/usr/local/bin/ssh-audit-log"
args = ["--user", "%u", "--key-type", "%t", "--fingerprint", "%f"]
enabled = true
timeout = 10
user = "audit"
readonly = true  # Don't include output in authorized keys
```

## Configuration Options

### Required Fields
- `name`: A descriptive name for the command
- `command`: The command/script to execute

### Optional Fields
- `args`: Array of arguments to pass to the command
- `enabled`: Whether this command is enabled (default: true)
- `timeout`: Timeout in seconds for command execution (default: 30)
- `user`: UNIX user to run the command as (only when ssh-auth-cmd runs as root)
- `readonly`: If true, discard stdout output (useful for logging/auditing)

## OpenSSH Placeholder Support

The following OpenSSH placeholders are supported in the `args` array:

- `%C`: Connection specification (user, client IP, client port, server IP, server port)
- `%D`: Routing domain
- `%f`: Key fingerprint
- `%h`: Hostname
- %k`: Key being offered for authentication
- `%t`: Key type
- `%U`: Original username (before any transformations)
- `%u`: Username being authenticated
- `%%`: Literal `%` character

### Example with Multiple Placeholders
```toml
name = "comprehensive_auth"
command = "/usr/local/bin/auth-checker"
args = [
    "--user", "%u",
    "--original-user", "%U", 
    "--hostname", "%h",
    "--connection", "%C",
    "--key-type", "%t",
    "--fingerprint", "%f",
    "--key", "%k",
    "--domain", "%D",
    "--literal-percent", "%%"
]
```

## OpenSSH Configuration

When using the install command, ssh-auth-cmd configures OpenSSH as:

```
AuthorizedKeysCommand /usr/local/bin/ssh-auth-cmd key-cmd -c %C -D %D -f %f -h %h -k %k -t %t -U %U -u %u
AuthorizedKeysCommandUser root
```

This exhaustively uses all OpenSSH substitution variables currently defined.

## User Switching

When `ssh-auth-cmd` runs as root (recommended), you can specify different users for each command:

- If `user` is specified in a command config, that command runs as the specified user
- If `user` is not specified, the command runs as the same user as `ssh-auth-cmd`
- If `ssh-auth-cmd` is not running as root, the `user` field is ignored

This allows for principle of least privilege - each command can run with only the permissions it needs.

## Commands and Usage

### Key Command Mode (used by OpenSSH)
```bash
ssh-auth-cmd key-cmd -c %C -D %D -f %f -h %h -k %k -t %t -U %U -u %u
```

This is the mode OpenSSH calls. It processes all enabled configurations and outputs authorized keys.

### Configuration Check
```bash
sudo ssh-auth-cmd config-check
```

Validates:
- Configuration directory and file permissions
- Configuration file syntax
- Placeholder substitution validity
- Command binary permissions
- That all command binaries are only writable by root

### Installation
```bash
# Install with default settings (AuthorizedKeysCommandUser root)
sudo ssh-auth-cmd install

# Install with specific user
sudo ssh-auth-cmd install --user nobody

# Install with custom sshd_config location
sudo ssh-auth-cmd install --config /etc/ssh/sshd_config.custom
```

The install command:
- Migrates existing `AuthorizedKeysCommand` to a config file in `/etc/ssh/auth_cmd.d/`
- Comments out the old configuration
- Adds the new ssh-auth-cmd configuration
- Preserves existing `AuthorizedKeysCommandUser` settings when migrating
- Will not overwrite existing files in `/etc/ssh/auth_cmd.d/`

## Security Considerations

### File Permissions
All configuration files and the configuration directory must have secure permissions:

```bash
# Set proper permissions
sudo chown -R root:root /etc/ssh/auth_cmd.d/
sudo chmod 755 /etc/ssh/auth_cmd.d/
sudo chmod 600 /etc/ssh/auth_cmd.d/*.toml
```

The `config-check` command verifies these permissions automatically.

### Command Security
- All configured command binaries must be owned by root and not writable by others
- Commands run with the privileges of the specified `user` (or the user running ssh-auth-cmd)
- Use the `readonly` flag for commands that should only log/audit without providing keys

### User Isolation
Different commands can run as different users for security isolation:
- LDAP queries might run as a dedicated `ldap-auth` user
- Database queries might run as a `db-auth` user
- Local file access might run as `nobody`
- Audit logging might run as an `audit` user

## Example Configurations

### Basic Local + LDAP Setup

`/etc/ssh/auth_cmd.d/01-local.toml`:
```toml
name = "local_keys"
command = "cat"
args = ["/home/%u/.ssh/authorized_keys"]
enabled = true
timeout = 30
user = "nobody"
```

`/etc/ssh/auth_cmd.d/02-ldap.toml`:
```toml
name = "ldap_lookup"
command = "/usr/local/bin/ldap-ssh-keys"
args = ["--user", "%u", "--hostname", "%h"]
enabled = true
timeout = 60
user = "ldap-auth"
```

### Enterprise Setup with Audit Trail

`/etc/ssh/auth_cmd.d/01-audit.toml`:
```toml
name = "connection_audit"
command = "/usr/local/bin/log-ssh-attempt"
args = [
    "--user", "%u",
    "--original-user", "%U",
    "--connection", "%C",
    "--hostname", "%h",
    "--key-fingerprint", "%f",
    "--key-type", "%t"
]
enabled = true
timeout = 10
user = "audit"
readonly = true  # Just for logging, don't provide keys
```

`/etc/ssh/auth_cmd.d/02-corporate-keys.toml`:
```toml
name = "corporate_ldap"
command = "/usr/local/bin/corporate-auth"
args = ["--user", "%u", "--domain", "corp.example.com"]
enabled = true
timeout = 60
user = "corp-auth"
```

`/etc/ssh/auth_cmd.d/03-emergency.toml`:
```toml
name = "emergency_access"
command = "/usr/local/bin/emergency-keys"
args = ["--user", "%u", "--validate-emergency"]
enabled = true
timeout = 30
user = "emergency-auth"
```

### Development/Testing Setup

`/etc/ssh/auth_cmd.d/01-local.toml`:
```toml
name = "local_keys"
command = "cat"
args = ["/home/%u/.ssh/authorized_keys"]
enabled = true
timeout = 30
```

`/etc/ssh/auth_cmd.d/02-shared-dev.toml`:
```toml
name = "shared_dev_keys"
command = "cat"
args = ["/etc/ssh/shared_dev_keys"]
enabled = true
timeout = 10
```

## Migration from Single Configuration

If you're migrating from the original single-file configuration:

1. Run the install command to automatically migrate:
```bash
sudo ssh-auth-cmd install
```

2. The installer will:
   - Move your existing `AuthorizedKeysCommand` to a config file
   - Comment out the old configuration
   - Install the new ssh-auth-cmd configuration

3. Verify the migration:
```bash
sudo ssh-auth-cmd config-check
```

## Troubleshooting

### Configuration Issues
```bash
# Check all configurations
sudo ssh-auth-cmd config-check

# Test manually for a specific user
sudo ssh-auth-cmd key-cmd -u testuser

# Test with full OpenSSH context
sudo ssh-auth-cmd key-cmd -c "testuser,192.168.1.100,22,10.0.0.1,22" -u testuser -h hostname.example.com
```

### Permission Problems
```bash
# Fix directory permissions
sudo chown -R root:root /etc/ssh/auth_cmd.d/
sudo chmod 755 /etc/ssh/auth_cmd.d/
sudo chmod 600 /etc/ssh/auth_cmd.d/*.toml

# Check command permissions
ls -la /usr/local/bin/your-auth-command
```

### SSH Debug Mode
Enable SSH debug logging to see what's happening:
```bash
# In /etc/ssh/sshd_config
LogLevel DEBUG

# Then check logs
sudo tail -f /var/log/auth.log
```

### Common Issues

1. **"Configuration directory is writable by group or others"**
   - Fix: `sudo chmod 755 /etc/ssh/auth_cmd.d/`

2. **"Configuration file is writable by group or others"**
   - Fix: `sudo chmod 600 /etc/ssh/auth_cmd.d/*.toml`

3. **"Command is not owned by root"**
   - Fix: `sudo chown root:root /path/to/command`

4. **"Invalid placeholder"**
   - Check that you're only using supported placeholders: %C, %D, %f, %h, %k, %t, %U, %u, %%

5. **"User not found"**
   - Ensure the user specified in the `user` field exists on the system

## Performance Considerations

- Commands run sequentially in alphabetical order by filename
- Set appropriate timeouts to prevent hanging connections
- Use `readonly = true` for audit/logging commands that don't provide keys
- Consider disabling unnecessary commands in production environments

## Best Practices

1. **Naming Convention**: Use numbered prefixes (01-, 02-, etc.) to control execution order
2. **User Separation**: Run different commands as different users for security isolation
3. **Timeouts**: Set conservative timeouts to prevent hanging SSH connections
4. **Auditing**: Use readonly commands for comprehensive audit logging
5. **Testing**: Always test configurations with `config-check` before deployment
6. **Monitoring**: Monitor command execution times and failure rates
7. **Backup**: Keep backups of working configurations before making changes

## Integration Examples

### With HashiCorp Vault
```toml
name = "vault_ssh_ca"
command = "/usr/local/bin/vault-ssh-helper"
args = ["-mode", "ca", "-username", "%u"]
enabled = true
timeout = 45
user = "vault-ssh"
```

### With FreeIPA/Red Hat IdM
```toml
name = "ipa_keys"
command = "/usr/bin/sss_ssh_authorizedkeys"
args = ["%u"]
enabled = true
timeout = 30
user = "sssd"
```

### With Custom Database
```toml
name = "db_keys"
command = "/usr/local/bin/db-ssh-keys"
args = [
    "--user", "%u",
    "--client-ip", "%C",
    "--hostname", "%h"
]
enabled = true
timeout = 60
user = "db-auth"
```

This comprehensive setup provides a secure, flexible, and maintainable way to chain multiple SSH authentication sources while maintaining full OpenSSH compatibility and security best practices.