On this page
Security Hardening
Security Hardening
Learn how to secure your Entra Auth Cli deployments for production environments.
Secure Token Storage
Use Temporary Files with Restricted Permissions
#!/bin/bash
set -euo pipefail
# Use secure temp file
TOKEN_FILE=$(mktemp)
trap "rm -f $TOKEN_FILE" EXIT
# Get token with restricted permissions
entra-auth-cli get-token -p my-profile --silent > "$TOKEN_FILE"
chmod 600 "$TOKEN_FILE"
# Use token
TOKEN=$(cat "$TOKEN_FILE")
curl -H "Authorization: Bearer $TOKEN" https://api.example.com
# File automatically deleted on exit
Never Log Tokens
# Bad: Token in logs
echo "Token: $TOKEN"
logger "Using token: $TOKEN"
# Good: Redact sensitive data
echo "Token acquired successfully"
logger "Authentication completed"
Profile Separation
Environment-Specific Profiles
Create separate profiles for each environment:
# Development
entra-auth-cli config create
# Name: dev-graph
# Client ID: <dev-app-id>
# Tenant ID: <dev-tenant-id>
# Scope: https://graph.microsoft.com/User.Read
# Staging
entra-auth-cli config create
# Name: staging-graph
# Client ID: <staging-app-id>
# Tenant ID: <staging-tenant-id>
# Scope: https://graph.microsoft.com/User.Read
# Production
entra-auth-cli config create
# Name: prod-graph
# Client ID: <prod-app-id>
# Tenant ID: <prod-tenant-id>
# Scope: https://graph.microsoft.com/.default
Never Mix Environments
# Good: Clear environment separation
entra-auth-cli get-token -p dev-graph # Development
entra-auth-cli get-token -p prod-graph # Production
# Bad: Shared profiles across environments
entra-auth-cli get-token -p shared-graph # Risk of production data exposure
Secret Rotation
Regular Rotation Schedule
#!/bin/bash
rotate_secret() {
local profile=$1
local new_secret=$2
echo "Rotating secret for profile: $profile"
# Update profile with new secret
entra-auth-cli config edit -p "$profile" <<EOF
3
$new_secret
q
EOF
# Test new secret
if entra-auth-cli get-token -p "$profile" --silent > /dev/null; then
echo "✓ Secret rotation successful"
# Optionally revoke old secret in Azure Portal
echo "Don't forget to revoke old secret in Azure Portal"
return 0
else
echo "✗ Secret rotation failed"
echo "Rolling back..."
return 1
fi
}
# Usage
NEW_SECRET=$(az keyvault secret show --name prod-secret --vault-name my-vault --query value -o tsv)
rotate_secret "prod-service-principal" "$NEW_SECRET"
Automated Rotation
#!/bin/bash
set -euo pipefail
# Rotation interval: 90 days
ROTATION_INTERVAL_DAYS=90
SECRET_NAME="entra-auth-cli-prod-secret"
KEY_VAULT="my-prod-vault"
# Check last rotation date
last_rotation=$(az keyvault secret show \
--name "$SECRET_NAME-last-rotation" \
--vault-name "$KEY_VAULT" \
--query value -o tsv 2>/dev/null || echo "0")
current_date=$(date +%s)
days_since_rotation=$(( (current_date - last_rotation) / 86400 ))
if [ $days_since_rotation -gt $ROTATION_INTERVAL_DAYS ]; then
echo "Secret is $days_since_rotation days old, rotating..."
# Generate new secret in Azure
new_secret=$(az ad app credential reset \
--id <app-id> \
--append \
--query password -o tsv)
# Update profile
rotate_secret "prod-profile" "$new_secret"
# Record rotation date
az keyvault secret set \
--name "$SECRET_NAME-last-rotation" \
--vault-name "$KEY_VAULT" \
--value "$current_date"
else
echo "Secret is $days_since_rotation days old, no rotation needed"
fi
Least Privilege
Scope Restriction
Always use the minimum required scopes:
# Good: Specific scope
entra-auth-cli get-token -p my-profile \
--scope "https://graph.microsoft.com/User.Read"
# Bad: Over-permissive
entra-auth-cli get-token -p my-profile \
--scope "https://graph.microsoft.com/.default" # Grants all consented permissions
Service Principal RBAC
Assign minimum required Azure RBAC roles:
# Good: Specific role
az ad sp create-for-rbac --name "entra-auth-cli-deployment" \
--role "Contributor" \
--scopes "/subscriptions/xxx/resourceGroups/my-rg"
# Bad: Over-permissive
az ad sp create-for-rbac --name "entra-auth-cli-deployment" \
--role "Owner" \
--scopes "/subscriptions/xxx" # Full subscription access
Certificate Security
Use Certificates for Production
Prefer certificates over client secrets for production:
# Create certificate with strong key
openssl req -x509 -newkey rsa:4096 \
-keyout key.pem -out cert.pem \
-days 730 -nodes \
-subj "/CN=MyProductionApp"
# Convert to PFX
openssl pkcs12 -export \
-in cert.pem -inkey key.pem \
-out certificate.pfx \
-password pass:$(openssl rand -base64 32)
Secure Certificate Storage
# Create secure directory
mkdir -p ~/.entra-auth-cli/certs
chmod 700 ~/.entra-auth-cli/certs
# Store certificate with restricted permissions
cp certificate.pfx ~/.entra-auth-cli/certs/
chmod 600 ~/.entra-auth-cli/certs/certificate.pfx
# Never store in git
echo "*.pfx" >> .gitignore
echo "*.p12" >> .gitignore
Network Security
Use HTTPS Only
# Good: HTTPS
curl -H "Authorization: Bearer $TOKEN" \
https://graph.microsoft.com/v1.0/me
# Bad: HTTP (never use)
curl -H "Authorization: Bearer $TOKEN" \
http://api.example.com/data # Token exposed in plaintext
Proxy Configuration
# Use corporate proxy
export HTTPS_PROXY="https://proxy.corp.com:8080"
export HTTP_PROXY="http://proxy.corp.com:8080"
entra-auth-cli get-token -p my-profile
Audit and Monitoring
Log Authentication Attempts
#!/bin/bash
log_auth() {
local profile=$1
local status=$2
logger -t entra-auth-cli \
"Authentication attempt: profile=$profile status=$status user=$(whoami) host=$(hostname)"
}
# Get token with logging
if TOKEN=$(entra-auth-cli get-token -p prod-profile --silent); then
log_auth "prod-profile" "success"
else
log_auth "prod-profile" "failure"
exit 1
fi
Monitor Token Usage
#!/bin/bash
# Track token acquisition
echo "$(date +%s),$(whoami),prod-profile,acquired" >> /var/log/token-usage.csv
# Alert on unusual patterns
token_count=$(grep -c "$(date +%Y-%m-%d)" /var/log/token-usage.csv)
if [ $token_count -gt 100 ]; then
# Send alert
echo "High token usage detected: $token_count requests today" | \
mail -s "Token Usage Alert" security@example.com
fi
Multi-Environment Setup
Directory Structure
~/.entra-auth-cli/
├── dev/
│ ├── profiles.json
│ └── certs/
├── staging/
│ ├── profiles.json
│ └── certs/
└── prod/
├── profiles.json
└── certs/
Environment-Specific Configuration
#!/bin/bash
# Set environment
ENVIRONMENT=${1:-dev}
export entra-auth-cli_CONFIG_PATH="$HOME/.entra-auth-cli/$ENVIRONMENT"
# Ensure directory exists
mkdir -p "$entra-auth-cli_CONFIG_PATH"
# Get token
entra-auth-cli get-token -p "$ENVIRONMENT-profile"
Secrets Management
Use External Secret Managers
Azure Key Vault:
#!/bin/bash
# Retrieve secret from Key Vault
CLIENT_SECRET=$(az keyvault secret show \
--name prod-client-secret \
--vault-name my-vault \
--query value -o tsv)
# Use secret (avoid storing in profile)
entra-auth-cli get-token -p prod-profile --client-secret "$CLIENT_SECRET"
HashiCorp Vault:
#!/bin/bash
# Retrieve secret from Vault
CLIENT_SECRET=$(vault kv get -field=client_secret secret/entra-auth-cli/prod)
# Use secret
entra-auth-cli get-token -p prod-profile --client-secret "$CLIENT_SECRET"
Compliance
GDPR/Privacy
- Never log personally identifiable information (PII)
- Use encrypted storage for sensitive data
- Implement data retention policies
- Document data processing activities
SOC 2
- Enable audit logging
- Implement access controls
- Rotate secrets regularly
- Monitor for security events
- Conduct regular security reviews
HIPAA
- Use encryption at rest and in transit
- Implement access logging
- Enforce strong authentication
- Regular security audits
- Incident response procedures
Security Checklist
Before Production
- Use certificates instead of client secrets
- Implement secret rotation
- Separate profiles per environment
- Restrict file permissions (600 for secrets)
- Enable audit logging
- Use least privilege scopes
- Test token expiration handling
- Document security procedures
- Set up monitoring and alerts
- Review Azure AD app permissions
Regular Maintenance
- Rotate secrets every 90 days
- Review audit logs monthly
- Update to latest CLI version
- Review app registrations quarterly
- Test disaster recovery procedures
- Update documentation
- Security training for team
- Penetration testing annually