npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- Organization needs centralized privileged credential management across hybrid infrastructure
- Compliance requirements mandate privileged access controls (SOX, PCI-DSS, HIPAA, NIST 800-53)
- Service accounts and shared credentials are stored in spreadsheets or plaintext files
- Need to implement automated password rotation for privileged accounts
- Require session recording and keystroke logging for privileged user activity
- Migrating from manual PAM processes to an enterprise vault solution
Do not use for standard end-user password management; Delinea Secret Server is designed for privileged and shared account credential management requiring enterprise-grade controls.
Prerequisites
- Delinea Secret Server license (On-Premises or Cloud)
- Windows Server 2019/2022 for on-premises deployment with IIS and SQL Server
- Active Directory service account with read permissions for discovery
- SSL/TLS certificate for web interface encryption
- Network connectivity to target systems for password rotation
- PowerShell 5.1+ for automation scripts
Workflow
Step 1: Deploy Secret Server Infrastructure
Install and configure the Secret Server application server:
# Pre-installation checks for on-premises deployment
# Verify IIS is installed with required features
Import-Module ServerManager
Install-WindowsFeature Web-Server, Web-Asp-Net45, Web-Windows-Auth, Web-Mgmt-Console
# Verify SQL Server connectivity
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = "Server=sql01.corp.local;Database=master;Integrated Security=True"
$sqlConn.Open()
Write-Host "SQL Server connection successful: $($sqlConn.ServerVersion)"
$sqlConn.Close()
# Create Secret Server database
Invoke-Sqlcmd -ServerInstance "sql01.corp.local" -Query @"
CREATE DATABASE SecretServer
GO
ALTER DATABASE SecretServer SET RECOVERY FULL
GO
"@
# Download and run Secret Server installer
# Navigate to https://thy.center/ss/link/SSDownload for latest version
# Run setup.exe and follow the installation wizard
# Post-installation: Configure application pool
Import-Module WebAdministration
Set-ItemProperty "IIS:\AppPools\SecretServer" -Name processModel.identityType -Value SpecificUser
Set-ItemProperty "IIS:\AppPools\SecretServer" -Name processModel.userName -Value "CORP\svc-secretserver"Step 2: Configure Secret Templates and Folder Structure
Define secret templates and organize the vault hierarchy:
# Connect to Secret Server API
$baseUrl = "https://pam.corp.local/SecretServer"
$creds = @{
username = "ss-admin"
password = $env:SS_ADMIN_PASSWORD
grant_type = "password"
}
$token = (Invoke-RestMethod "$baseUrl/oauth2/token" -Method POST -Body $creds).access_token
$headers = @{ Authorization = "Bearer $token" }
# Create folder structure for organizing secrets
$folders = @(
@{ folderName = "Windows Servers"; parentFolderId = -1; inheritPermissions = $false },
@{ folderName = "Linux Servers"; parentFolderId = -1; inheritPermissions = $false },
@{ folderName = "Network Devices"; parentFolderId = -1; inheritPermissions = $false },
@{ folderName = "Cloud Accounts"; parentFolderId = -1; inheritPermissions = $false },
@{ folderName = "Service Accounts"; parentFolderId = -1; inheritPermissions = $false },
@{ folderName = "Database Accounts"; parentFolderId = -1; inheritPermissions = $false }
)
foreach ($folder in $folders) {
Invoke-RestMethod "$baseUrl/api/v1/folders" -Method POST -Headers $headers `
-ContentType "application/json" -Body ($folder | ConvertTo-Json)
}
# Create custom secret template for database credentials
$template = @{
name = "Database Credential"
fields = @(
@{ name = "Server"; isRequired = $true; fieldType = "Text" },
@{ name = "Port"; isRequired = $true; fieldType = "Text" },
@{ name = "Database"; isRequired = $true; fieldType = "Text" },
@{ name = "Username"; isRequired = $true; fieldType = "Text" },
@{ name = "Password"; isRequired = $true; fieldType = "Password" },
@{ name = "Connection String"; isRequired = $false; fieldType = "Notes" }
)
}
Invoke-RestMethod "$baseUrl/api/v1/secret-templates" -Method POST -Headers $headers `
-ContentType "application/json" -Body ($template | ConvertTo-Json -Depth 3)Step 3: Configure Discovery and Account Onboarding
Set up automated discovery of privileged accounts across the environment:
# Configure Active Directory discovery source
$adDiscovery = @{
name = "Corporate AD Discovery"
discoverySourceType = "ActiveDirectory"
active = $true
settings = @{
domainName = "corp.local"
friendlyName = "Corporate Domain"
discoveryAccountId = 12 # Service account secret ID
ouFilters = @(
"OU=Servers,DC=corp,DC=local",
"OU=Workstations,DC=corp,DC=local"
)
}
scanInterval = 86400 # 24 hours
}
Invoke-RestMethod "$baseUrl/api/v1/discovery" -Method POST -Headers $headers `
-ContentType "application/json" -Body ($adDiscovery | ConvertTo-Json -Depth 3)
# Configure local account discovery for Windows servers
$localDiscovery = @{
name = "Windows Local Account Discovery"
discoverySourceType = "Machine"
active = $true
settings = @{
machineType = "Windows"
accountScanTemplate = "Windows Local Account"
dependencyScanTemplate = "Windows Service"
}
}
Invoke-RestMethod "$baseUrl/api/v1/discovery" -Method POST -Headers $headers `
-ContentType "application/json" -Body ($localDiscovery | ConvertTo-Json -Depth 3)
# Import discovered accounts as secrets
# After discovery runs, review and import found accounts
$discoveredAccounts = Invoke-RestMethod "$baseUrl/api/v1/discovery/status" -Headers $headers
Write-Host "Discovered $($discoveredAccounts.totalAccounts) accounts"
Write-Host " - Domain Admins: $($discoveredAccounts.domainAdmins)"
Write-Host " - Local Admins: $($discoveredAccounts.localAdmins)"
Write-Host " - Service Accounts: $($discoveredAccounts.serviceAccounts)"Step 4: Implement Password Rotation Policies
Configure automated password rotation with complexity requirements:
# Create password rotation policy
$rotationPolicy = @{
name = "High-Security 30-Day Rotation"
rotationIntervalDays = 30
passwordRequirements = @{
minimumLength = 24
maximumLength = 32
requireUpperCase = $true
requireLowerCase = $true
requireNumbers = $true
requireSymbols = $true
allowedSymbols = "!@#$%^&*()-_=+[]{}|;:,.<>?"
}
rotationType = "AutoChange"
autoChangeSchedule = @{
changeType = "RecurringSchedule"
recurrenceType = "Monthly"
dayOfMonth = 1
startTime = "02:00"
}
}
Invoke-RestMethod "$baseUrl/api/v1/remote-password-changing/configuration" -Method POST `
-Headers $headers -ContentType "application/json" -Body ($rotationPolicy | ConvertTo-Json -Depth 4)
# Configure Remote Password Changing (RPC) for Windows accounts
$rpcConfig = @{
secretId = 100 # Target secret
autoChangeEnabled = $true
autoChangeNextPassword = $true
privilegedAccountSecretId = 50 # Account used to perform the change
changePasswordUsing = "PrivilegedAccount"
}
Invoke-RestMethod "$baseUrl/api/v1/secrets/100/remote-password-changing" -Method PUT `
-Headers $headers -ContentType "application/json" -Body ($rpcConfig | ConvertTo-Json)
# Configure heartbeat monitoring to verify credential validity
$heartbeat = @{
enabled = $true
intervalMinutes = 60
onFailure = "SendAlert"
alertEmailGroupId = 5
}
Invoke-RestMethod "$baseUrl/api/v1/secrets/100/heartbeat" -Method PUT `
-Headers $headers -ContentType "application/json" -Body ($heartbeat | ConvertTo-Json)Step 5: Configure Session Recording and Monitoring
Enable session recording for privileged access sessions:
# Enable session recording policy
$sessionPolicy = @{
name = "Full Recording Policy"
recordSessions = $true
recordKeystrokes = $true
recordApplications = $true
maxSessionDurationMinutes = 480
requireComment = $true
requireTicketNumber = $true
ticketSystemId = 1 # ServiceNow integration
settings = @{
videoCodec = "H264"
videoQuality = "High"
captureInterval = 1000 # milliseconds
storageLocation = "\\\\fileserver\\SSRecordings"
retentionDays = 365
}
}
Invoke-RestMethod "$baseUrl/api/v1/secret-policy" -Method POST -Headers $headers `
-ContentType "application/json" -Body ($sessionPolicy | ConvertTo-Json -Depth 3)
# Configure session launcher for RDP sessions
$rdpLauncher = @{
launcherType = "RDP"
enableRecording = $true
enableDualControl = $true
approverGroupId = 10 # Security team group
connectAsSecretId = 100
settings = @{
useSSL = $true
restrictedEndpoints = @("192.168.1.0/24")
inactivityTimeout = 30 # minutes
}
}
Invoke-RestMethod "$baseUrl/api/v1/launchers" -Method POST -Headers $headers `
-ContentType "application/json" -Body ($rdpLauncher | ConvertTo-Json -Depth 3)
# Configure dual control / approval workflow
$approvalWorkflow = @{
name = "Tier-0 Account Approval"
requireApproval = $true
approvers = @(
@{ groupId = 10; requiredApprovals = 1 }
)
accessRequestExpirationMinutes = 60
notifyOnApproval = $true
notifyOnDenial = $true
}Step 6: Integrate with SIEM and Compliance Reporting
Connect Secret Server events to security monitoring:
# Configure Syslog forwarding to SIEM
$syslogConfig = @{
enabled = $true
syslogServer = "siem.corp.local"
port = 514
protocol = "TLS"
facility = "Auth"
severity = "Informational"
events = @(
"SecretView", "SecretEdit", "SecretCreate", "SecretDelete",
"PasswordChange", "PasswordChangeFailure",
"SessionStart", "SessionEnd",
"LoginFailure", "LoginSuccess",
"PermissionChange", "ApprovalRequest"
)
}
Invoke-RestMethod "$baseUrl/api/v1/configuration/syslog" -Method PUT -Headers $headers `
-ContentType "application/json" -Body ($syslogConfig | ConvertTo-Json -Depth 2)
# Generate compliance report
$report = @{
reportType = "PasswordCompliance"
dateRange = @{
startDate = (Get-Date).AddDays(-30).ToString("yyyy-MM-dd")
endDate = (Get-Date).ToString("yyyy-MM-dd")
}
filters = @{
folderIds = @(1, 2, 3, 4, 5, 6)
includeSubFolders = $true
}
}
$reportResult = Invoke-RestMethod "$baseUrl/api/v1/reports" -Method POST -Headers $headers `
-ContentType "application/json" -Body ($report | ConvertTo-Json -Depth 3)
# Display compliance summary
Write-Host "PAM Compliance Report"
Write-Host "====================="
Write-Host "Total Secrets: $($reportResult.totalSecrets)"
Write-Host "Rotation Compliant: $($reportResult.rotationCompliant) ($($reportResult.rotationCompliancePct)%)"
Write-Host "Heartbeat Healthy: $($reportResult.heartbeatHealthy) ($($reportResult.heartbeatHealthyPct)%)"
Write-Host "Password Age > 90d: $($reportResult.passwordAgeViolations)"
Write-Host "Orphaned Accounts: $($reportResult.orphanedAccounts)"Key Concepts
| Term | Definition |
|---|---|
| Privileged Access Management (PAM) | Security framework for controlling, monitoring, and auditing elevated access to critical systems and data through credential vaulting and session management |
| Secret | A stored credential or sensitive data item in the vault, including passwords, SSH keys, API tokens, and certificates |
| Remote Password Changing (RPC) | Automated mechanism that connects to target systems to rotate passwords according to defined policies without manual intervention |
| Heartbeat | Periodic check that validates stored credentials against target systems to ensure vault contents remain synchronized and functional |
| Dual Control | Security mechanism requiring approval from a second authorized user before granting access to highly sensitive secrets |
| Discovery | Automated scanning of infrastructure to identify privileged accounts, service accounts, and dependencies across Active Directory, servers, and network devices |
| Session Recording | Capture of complete privileged session activity including video, keystrokes, and application usage for audit and forensic review |
Tools & Systems
- Delinea Secret Server: Enterprise PAM solution providing credential vaulting, password rotation, session recording, and privileged access workflows
- Delinea Distributed Engine: Agent deployed in network segments to enable password changing and discovery across firewalled environments
- Secret Server REST API: RESTful API for programmatic secret management, automation, and integration with DevOps pipelines
- Secret Server SDK: .NET and PowerShell SDKs for application-level integration with Secret Server vault
Common Scenarios
Scenario: Migrating Shared Admin Credentials to Vault
Context: An organization stores 500+ shared administrator credentials in Excel spreadsheets and password-protected documents. Auditors flagged this as a critical finding requiring remediation within 90 days.
Approach:
- Deploy Secret Server with SQL Server backend and configure HTTPS access
- Design folder hierarchy mirroring the organizational structure (by department, system type, environment)
- Create secret templates matching the credential types in use (Windows, Linux, database, network device)
- Import existing credentials via CSV import or PowerShell bulk creation
- Configure discovery to find undocumented privileged accounts across AD and local systems
- Enable Remote Password Changing starting with non-production accounts to validate rotation
- Roll out session launchers to replace direct RDP/SSH connections
- Gradually enable dual control for Tier-0 accounts (Domain Admins, root accounts)
- Configure SIEM integration and compliance reporting for audit evidence
Pitfalls:
- Not identifying all service account dependencies before enabling password rotation (causes service outages)
- Enabling RPC for production accounts without testing in non-production first
- Setting rotation intervals too short for service accounts that require coordinated restarts
- Not configuring Distributed Engines for network segments separated by firewalls
Output Format
DELINEA SECRET SERVER PAM DEPLOYMENT REPORT
=============================================
Environment: Hybrid (On-Premises + Azure)
Version: Secret Server 11.6
Deployment Mode: On-Premises (High Availability)
VAULT STATISTICS
Total Secrets: 1,247
Windows Credentials: 523
Linux/SSH Keys: 312
Database Accounts: 198
Network Devices: 87
Cloud API Keys: 127
PASSWORD ROTATION STATUS
Auto-Change Enabled: 1,089 / 1,247 (87.3%)
Rotation Compliant: 1,056 / 1,089 (97.0%)
Heartbeat Healthy: 1,198 / 1,247 (96.1%)
Failed Rotations (30d): 12
SESSION MANAGEMENT
Active Sessions: 23
Recorded Sessions (30d): 4,567
Average Session Length: 22 minutes
Approval Requests (30d): 189 (174 approved, 15 denied)
DISCOVERY RESULTS
Scanned Systems: 2,340
Discovered Accounts: 3,891
Onboarded to Vault: 1,247 (32.1%)
Pending Review: 892
COMPLIANCE
SOX Controls Met: 12/12
PCI-DSS Requirements: 8/8
Password Age Violations: 3 (remediation in progress)References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.3 KB
API Reference: Implementing Delinea Secret Server for PAM
Libraries
requests (HTTP client for REST API)
- Install:
pip install requests - Used to interact with Secret Server REST API v1
Secret Server REST API
Authentication
- Endpoint:
POST /oauth2/token - Grant type:
password - Parameters:
username,password,domain(optional) - Returns:
access_token(Bearer token)
Secrets API
| Endpoint | Method | Description |
|---|---|---|
/api/v1/secrets |
GET | Search/list secrets |
/api/v1/secrets/{id} |
GET | Get secret by ID |
/api/v1/secrets |
POST | Create new secret |
/api/v1/secrets/{id} |
PUT | Update secret |
/api/v1/secrets/{id}/change-password |
POST | Trigger password rotation |
/api/v1/secrets/{id}/check-out |
POST | Check out for exclusive access |
/api/v1/secrets/{id}/check-in |
POST | Release checked-out secret |
/api/v1/secrets/{id}/audits |
GET | Audit trail for secret |
/api/v1/secrets/{id}/fields/{slug} |
GET | Get specific field value |
Folders API
| Endpoint | Method | Description |
|---|---|---|
/api/v1/folders |
GET | List folders |
/api/v1/folders/{id} |
GET | Get folder details |
/api/v1/folders |
POST | Create folder |
Administration API
| Endpoint | Method | Description |
|---|---|---|
/api/v1/users |
GET | List users |
/api/v1/roles |
GET | List roles |
/api/v1/secret-templates |
GET | List secret templates |
/api/v1/configuration/general |
GET | Server configuration |
Common Secret Templates
- Windows Account: Domain, username, password
- Unix Account (SSH): Host, username, private key
- SQL Server Account: Server, database, username, password
- Web Password: URL, username, password
Search Filters
filter.searchText-- Keyword searchfilter.folderId-- Filter by folderfilter.secretTemplateId-- Filter by templatefilter.includeSubFolders-- Include nested folders
External References
- Secret Server REST API: https://docs.delinea.com/online-help/secret-server/api-scripting/rest-api-reference/
- Secret Server SDK: https://github.com/DelineaXPM/python-tss-sdk
- PAM Best Practices: https://docs.delinea.com/online-help/secret-server/
Scripts 1
agent.py7.0 KB
#!/usr/bin/env python3
"""Delinea Secret Server PAM agent for privileged credential management."""
import json
import sys
import argparse
from datetime import datetime
try:
import requests
except ImportError:
print("Install requests: pip install requests")
sys.exit(1)
class SecretServerClient:
"""Client for Delinea Secret Server REST API."""
def __init__(self, base_url, username, password, domain=None):
self.base_url = base_url.rstrip("/")
self.session = requests.Session()
self.token = self._authenticate(username, password, domain)
self.session.headers.update({"Authorization": f"Bearer {self.token}"})
def _authenticate(self, username, password, domain):
"""Authenticate and retrieve OAuth2 bearer token."""
url = f"{self.base_url}/oauth2/token"
data = {"grant_type": "password", "username": username, "password": password}
if domain:
data["domain"] = domain
resp = self.session.post(url, data=data, timeout=30)
resp.raise_for_status()
return resp.json()["access_token"]
def search_secrets(self, search_text=None, folder_id=None, secret_template_id=None):
"""Search for secrets with optional filters."""
params = {}
if search_text:
params["filter.searchText"] = search_text
if folder_id:
params["filter.folderId"] = folder_id
if secret_template_id:
params["filter.secretTemplateId"] = secret_template_id
resp = self.session.get(f"{self.base_url}/api/v1/secrets", params=params, timeout=30)
resp.raise_for_status()
return resp.json().get("records", [])
def get_secret(self, secret_id):
"""Retrieve a secret by ID."""
resp = self.session.get(f"{self.base_url}/api/v1/secrets/{secret_id}", timeout=30)
resp.raise_for_status()
return resp.json()
def create_secret(self, name, template_id, folder_id, fields):
"""Create a new secret in the vault."""
items = [{"fieldId": fid, "itemValue": val} for fid, val in fields.items()]
data = {"name": name, "secretTemplateId": template_id,
"folderId": folder_id, "items": items}
resp = self.session.post(f"{self.base_url}/api/v1/secrets", json=data, timeout=30)
resp.raise_for_status()
return resp.json()
def get_secret_templates(self):
"""List available secret templates."""
resp = self.session.get(f"{self.base_url}/api/v1/secret-templates", timeout=30)
resp.raise_for_status()
return resp.json().get("records", [])
def get_folders(self, parent_id=None):
"""List folders, optionally under a parent."""
params = {}
if parent_id:
params["filter.parentFolderId"] = parent_id
resp = self.session.get(f"{self.base_url}/api/v1/folders", params=params, timeout=30)
resp.raise_for_status()
return resp.json().get("records", [])
def rotate_secret_password(self, secret_id):
"""Trigger password rotation for a secret (Remote Password Changing)."""
resp = self.session.post(
f"{self.base_url}/api/v1/secrets/{secret_id}/change-password", timeout=30)
resp.raise_for_status()
return resp.json()
def get_secret_audit(self, secret_id):
"""Get audit trail for a specific secret."""
resp = self.session.get(f"{self.base_url}/api/v1/secrets/{secret_id}/audits", timeout=30)
resp.raise_for_status()
return resp.json().get("records", [])
def checkout_secret(self, secret_id):
"""Check out a secret for exclusive access."""
resp = self.session.post(
f"{self.base_url}/api/v1/secrets/{secret_id}/check-out", timeout=30)
resp.raise_for_status()
return resp.json()
def checkin_secret(self, secret_id):
"""Check in a previously checked-out secret."""
resp = self.session.post(
f"{self.base_url}/api/v1/secrets/{secret_id}/check-in", timeout=30)
resp.raise_for_status()
return resp.json()
def get_users(self):
"""List all users."""
resp = self.session.get(f"{self.base_url}/api/v1/users", timeout=30)
resp.raise_for_status()
return resp.json().get("records", [])
def get_roles(self):
"""List all roles."""
resp = self.session.get(f"{self.base_url}/api/v1/roles", timeout=30)
resp.raise_for_status()
return resp.json().get("records", [])
def run_pam_audit(client):
"""Run a PAM security audit."""
print(f"\n{'='*60}")
print(f" DELINEA SECRET SERVER PAM AUDIT")
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*60}\n")
templates = client.get_secret_templates()
print(f"--- SECRET TEMPLATES ({len(templates)}) ---")
for t in templates[:10]:
print(f" [{t['id']}] {t['name']}")
folders = client.get_folders()
print(f"\n--- FOLDERS ({len(folders)}) ---")
for f in folders[:10]:
print(f" [{f['id']}] {f['folderName']}")
secrets = client.search_secrets()
print(f"\n--- SECRETS ({len(secrets)}) ---")
for s in secrets[:10]:
print(f" [{s['id']}] {s['name']} (Template: {s.get('secretTemplateName', 'N/A')})")
users = client.get_users()
print(f"\n--- USERS ({len(users)}) ---")
for u in users[:10]:
print(f" [{u['id']}] {u.get('userName', 'N/A')} - Enabled: {u.get('isDisabled', True)}")
roles = client.get_roles()
print(f"\n--- ROLES ({len(roles)}) ---")
for r in roles[:10]:
print(f" [{r['id']}] {r['name']}")
print(f"\n{'='*60}\n")
return {"templates": len(templates), "folders": len(folders),
"secrets": len(secrets), "users": len(users), "roles": len(roles)}
def main():
parser = argparse.ArgumentParser(description="Delinea Secret Server PAM Agent")
parser.add_argument("--url", required=True, help="Secret Server base URL")
parser.add_argument("--username", required=True, help="Username")
parser.add_argument("--password", required=True, help="Password")
parser.add_argument("--domain", help="AD domain (optional)")
parser.add_argument("--audit", action="store_true", help="Run PAM audit")
parser.add_argument("--search", help="Search secrets by keyword")
parser.add_argument("--rotate", type=int, help="Rotate password for secret ID")
parser.add_argument("--output", help="Save report to JSON")
args = parser.parse_args()
client = SecretServerClient(args.url, args.username, args.password, args.domain)
if args.audit:
report = run_pam_audit(client)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
elif args.search:
results = client.search_secrets(search_text=args.search)
for s in results:
print(f" [{s['id']}] {s['name']}")
elif args.rotate:
result = client.rotate_secret_password(args.rotate)
print(json.dumps(result, indent=2))
else:
parser.print_help()
if __name__ == "__main__":
main()