@fastmcp-oauth/kerberos-delegation
Version:
Kerberos delegation module for FastMCP OAuth framework - Windows Kerberos Constrained Delegation support
449 lines (337 loc) • 11.6 kB
Markdown
# @fastmcp-oauth/kerberos-delegation
Kerberos delegation module for the MCP OAuth framework - provides Windows Kerberos Constrained Delegation support.
## Overview
This package is a **reference implementation** demonstrating how to build delegation modules for the MCP OAuth framework. It provides Kerberos-based authentication and delegation using:
- **S4U2Self**: Service for User to Self (obtain ticket on behalf of user)
- **S4U2Proxy**: Service for User to Proxy (delegate to backend services)
## Installation
```bash
npm install @fastmcp-oauth/kerberos-delegation
```
This package is an **optional** dependency of `fastmcp-oauth`. The core framework works without Kerberos support.
## Platform Requirements
### Windows (Domain-Joined)
- **Windows Server** with Active Directory
- **Node.js** 18.0.0 or higher
- **Kerberos** configured service account with delegation rights
- Uses **Windows SSPI** (Security Support Provider Interface)
### Linux
- **Node.js** 18.0.0 or higher
- **MIT Kerberos** (`krb5-user` package)
- **Keytab file** for service account
- Network access to Active Directory KDC
### Windows (Non-Domain-Joined)
See [Non-Domain-Joined Windows Setup](#non-domain-joined-windows-setup) below
## Features
### Security
- ✅ Windows SSPI integration via node-kerberos
- ✅ Kerberos Constrained Delegation (S4U2Self/S4U2Proxy)
- ✅ Ticket caching for performance
- ✅ Automatic ticket renewal
- ✅ Audit logging for all delegation operations
### Kerberos Operations
- **S4U2Self**: Obtain Kerberos ticket on behalf of user
- **S4U2Proxy**: Act on behalf of user to backend services
- **Ticket Cache**: Cache Kerberos tickets with TTL
## Usage
### Basic Kerberos Delegation
```typescript
import { KerberosDelegationModule } from '@fastmcp-oauth/kerberos-delegation';
import { DelegationRegistry } from 'fastmcp-oauth/delegation';
const kerberosModule = new KerberosDelegationModule();
await kerberosModule.initialize({
servicePrincipalName: 'HTTP/mcp-server.company.com',
realm: 'COMPANY.COM',
kdcServer: 'dc01.company.com',
ticketCache: {
enabled: true,
ttlSeconds: 3600,
maxEntries: 1000
}
});
// Register with framework
const registry = new DelegationRegistry();
registry.register(kerberosModule);
// Perform S4U2Self delegation
const result = await registry.delegate(
'kerberos',
session,
's4u2self',
{
action: 's4u2self',
userPrincipalName: 'ALICE@COMPANY.COM'
}
);
```
### S4U2Proxy Delegation
```typescript
// Delegate to backend service
const result = await registry.delegate(
'kerberos',
session,
's4u2proxy',
{
action: 's4u2proxy',
userPrincipalName: 'ALICE@COMPANY.COM',
targetService: 'HTTP/backend.company.com'
}
);
```
## API
### KerberosDelegationModule
#### Actions
- **`s4u2self`** - Obtain Kerberos ticket on behalf of user
```typescript
{
action: 's4u2self',
userPrincipalName: 'ALICE@COMPANY.COM'
}
```
- **`s4u2proxy`** - Act on behalf of user to backend service
```typescript
{
action: 's4u2proxy',
userPrincipalName: 'ALICE@COMPANY.COM',
targetService: 'HTTP/backend.company.com'
}
```
- **`ticket-cache-stats`** - Get ticket cache statistics
```typescript
{
action: 'ticket-cache-stats'
}
```
## Configuration
### Kerberos Configuration
```typescript
{
servicePrincipalName: string; // SPN of MCP server
realm: string; // Kerberos realm (e.g., COMPANY.COM)
kdcServer: string; // Key Distribution Center hostname
ticketCache?: {
enabled: boolean; // Enable ticket caching
ttlSeconds: number; // Ticket TTL (default: 3600)
maxEntries: number; // Max cached tickets (default: 1000)
};
}
```
## Active Directory Setup
### Service Account Configuration
1. Create service account for MCP server:
```powershell
New-ADUser -Name "mcp-service" -UserPrincipalName "mcp-service@COMPANY.COM"
```
2. Set Service Principal Name (SPN):
```powershell
setspn -A HTTP/mcp-server.company.com COMPANY\mcp-service
```
3. Enable delegation rights:
```powershell
# Enable constrained delegation
Set-ADUser -Identity "mcp-service" -Add @{'msDS-AllowedToDelegateTo'=@('HTTP/backend.company.com')}
```
4. Enable protocol transition (for S4U2Self):
```powershell
Set-ADAccountControl -Identity "mcp-service" -TrustedToAuthForDelegation $true
```
## Security Considerations
### Delegation Rights
Kerberos Constrained Delegation requires:
- Service account with `TrustedToAuthForDelegation` flag
- Specific services listed in `msDS-AllowedToDelegateTo` attribute
- Active Directory domain functional level 2003+
### Ticket Security
- Tickets are cached in memory only (not persisted to disk)
- Ticket cache supports automatic expiration and renewal
- All delegation operations are audit logged
## Platform-Specific Configuration
### Linux Setup with Keytab
On Linux, the recommended approach is to use a **keytab file** for authentication:
#### 1. Generate Keytab on Active Directory
```powershell
# On Windows AD Domain Controller
ktpass -princ HTTP/mcp-server@COMPANY.COM -mapuser svc-mcp-server `
-pass YourSecurePassword123! -out mcp-server.keytab `
-ptype KRB5_NT_PRINCIPAL
```
#### 2. Copy Keytab to Linux Server
```bash
# Copy keytab to Linux server
scp mcp-server.keytab linux-server:/etc/keytabs/
chmod 600 /etc/keytabs/mcp-server.keytab
chown node-app-user:node-app-user /etc/keytabs/mcp-server.keytab
```
#### 3. Install MIT Kerberos
```bash
# Ubuntu/Debian
sudo apt-get install krb5-user
# RHEL/CentOS
sudo yum install krb5-workstation
```
#### 4. Configure Kerberos (`/etc/krb5.conf`)
```ini
[libdefaults]
default_realm = COMPANY.COM
dns_lookup_kdc = true
dns_lookup_realm = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
[realms]
COMPANY.COM = {
kdc = dc01.company.com:88
admin_server = dc01.company.com:749
default_domain = company.com
}
[domain_realm]
.company.com = COMPANY.COM
company.com = COMPANY.COM
```
#### 5. Update Configuration to Use Keytab
```json
{
"delegation": {
"modules": {
"kerberos": {
"enabled": true,
"domainController": "dc01.company.com",
"servicePrincipalName": "HTTP/mcp-server",
"realm": "COMPANY.COM",
"kdc": "dc01.company.com:88",
"serviceAccount": {
"username": "svc-mcp-server",
"keytabPath": "/etc/keytabs/mcp-server.keytab"
}
}
}
}
}
```
#### 6. Test Keytab
```bash
# Obtain ticket using keytab
kinit -kt /etc/keytabs/mcp-server.keytab svc-mcp-server@COMPANY.COM
# Verify ticket
klist
# Expected output:
# Ticket cache: FILE:/tmp/krb5cc_1000
# Default principal: svc-mcp-server@COMPANY.COM
```
### Non-Domain-Joined Windows Setup
For **non-domain-joined Windows machines**, you have several options:
#### Option 1: MIT Kerberos for Windows (Recommended)
Install MIT Kerberos for Windows to get the same capabilities as Linux:
**Step 1: Install MIT Kerberos**
```powershell
# Download from: https://web.mit.edu/kerberos/dist/
# Or use Chocolatey:
choco install kerberos-for-windows
```
**Step 2: Configure Kerberos (`C:\ProgramData\MIT\Kerberos5\krb5.ini`)**
```ini
[libdefaults]
default_realm = COMPANY.COM
dns_lookup_kdc = true
dns_lookup_realm = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
[realms]
COMPANY.COM = {
kdc = dc01.company.com:88
admin_server = dc01.company.com:749
default_domain = company.com
}
[domain_realm]
.company.com = COMPANY.COM
company.com = COMPANY.COM
```
**Step 3: Obtain Kerberos Ticket**
```powershell
# Using password
kinit svc-mcp-server@COMPANY.COM
# Or using keytab (recommended)
kinit -kt C:\keytabs\mcp-server.keytab svc-mcp-server@COMPANY.COM
# Verify ticket
klist
```
**Step 4: Run MCP Server**
The `kerberos` npm package will automatically detect MIT Kerberos and use it instead of SSPI.
#### Option 2: Windows Credential Manager (SSPI)
Cache credentials using Windows built-in tools:
```powershell
# Add credentials to Windows Credential Manager
cmdkey /generic:TERMSRV/dc01.company.com /user:COMPANY\svc-mcp-server /pass:YourPassword123!
# Verify
cmdkey /list
# Start a new session with domain credentials
runas /netonly /user:COMPANY\svc-mcp-server "powershell.exe"
# In the new PowerShell window, run the server
cd "C:\path\to\mcp-oauth"
npm start
```
#### Option 3: ksetup Configuration
Configure the non-domain-joined machine to trust the domain:
```powershell
# Run as Administrator
ksetup /setdomain COMPANY.COM
ksetup /addkdc COMPANY.COM dc01.company.com
# Map realm to domain
ksetup /addhosttorealmmap dc01.company.com COMPANY.COM
# Reboot required
shutdown /r /t 0
```
After reboot, use `runas /netonly` as shown in Option 2.
#### Option 4: WSL2 with MIT Kerberos
Run the MCP server in WSL2 (Ubuntu) where MIT Kerberos works natively:
```bash
# In WSL2 Ubuntu
sudo apt-get install krb5-user
# Configure /etc/krb5.conf (same as Linux setup above)
sudo nano /etc/krb5.conf
# Use keytab
kinit -kt /etc/keytabs/mcp-server.keytab svc-mcp-server@COMPANY.COM
# Run server
npm start
```
### Platform Comparison
| Feature | Windows (Domain-Joined) | Linux | Windows (Non-Domain) |
|---------|------------------------|-------|---------------------|
| **Kerberos Library** | Windows SSPI | MIT Kerberos | MIT Kerberos (recommended) |
| **Password Auth** | ❌ Not supported | ✅ Supported | ✅ With MIT Kerberos |
| **Keytab Auth** | ❌ Not supported by SSPI | ✅ **Recommended** | ✅ With MIT Kerberos |
| **Current User Credentials** | ✅ Default | ⚠️ Requires `kinit` | ⚠️ Requires `kinit` |
| **Setup Complexity** | Low (automatic) | Medium (keytab setup) | High (MIT Kerberos install) |
| **Production Ready** | ✅ Yes | ✅ Yes | ⚠️ Yes (with MIT Kerberos) |
## Troubleshooting
### Common Issues
**Issue: "Kerberos client initialization failed"**
- Verify service account has SPN configured
- Check KDC server is reachable
- Ensure Windows SSPI is available (or MIT Kerberos on Linux)
**Issue: "No credentials are available in the security package" (Windows SSPI)**
- **Cause**: Windows SSPI doesn't support password authentication; it requires cached credentials
- **Solution 1**: Install MIT Kerberos for Windows (see [Option 1](#option-1-mit-kerberos-for-windows-recommended))
- **Solution 2**: Run server with `runas /netonly` (see [Option 2](#option-2-windows-credential-manager-sspi))
- **Solution 3**: Use domain-joined machine where credentials are automatically cached
**Issue: "S4U2Self failed: KDC_ERR_BADOPTION"**
- Service account missing `TrustedToAuthForDelegation` flag
- Protocol transition not enabled in AD
**Issue: "S4U2Proxy failed: KDC_ERR_BADOPTION"**
- Target service not in `msDS-AllowedToDelegateTo` list
- Constrained delegation not configured
**Issue: "Keytab contains no suitable keys" (Linux)**
- Keytab file doesn't match the service principal name
- Regenerate keytab with correct SPN using `ktpass`
### Debug Mode
Enable debug logging:
```typescript
const kerberosModule = new KerberosDelegationModule();
kerberosModule.setDebugMode(true);
```
## License
MIT
## See Also
- [MCP OAuth Framework](https://github.com/yourorg/mcp-oauth)
- [Framework Extension Guide](../../Docs/EXTENDING.md)
- [Kerberos Constrained Delegation (Microsoft Docs)](https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview)