jan-karel.nl
Home / Securitymaatregelen / Cloudbeveiliging / Cloud Persistentie Voorkomen

Cloud Persistentie Voorkomen

Cloud Persistentie Voorkomen

Policy In Code, Niet In Hoop

Cloudomgevingen veranderen snel. Daarom moet beveiliging hier standaard en geautomatiseerd meebewegen.

Bij Cloud Persistentie Voorkomen is succes afhankelijk van policy-as-code en controles die continu meedraaien in de delivery-keten.

Zo houd je snelheid in de cloud, zonder dat veiligheid afhankelijk wordt van handmatig geluk.

Directe maatregelen (15 minuten)

Waarom dit telt

De kern van Cloud Persistentie Voorkomen is risicoreductie in de praktijk. Technische context ondersteunt de maatregelkeuze, maar implementatie en borging staan centraal.

Verdedigingsmaatregelen

CloudTrail Monitoring

# CloudTrail events die op persistentie kunnen wijzen
# IAM-gerelateerde events
aws logs filter-log-events \
  --log-group-name CloudTrail/management-events \
  --filter-pattern '{
    ($.eventName = "CreateUser") ||
    ($.eventName = "CreateAccessKey") ||
    ($.eventName = "CreateRole") ||
    ($.eventName = "UpdateAssumeRolePolicy") ||
    ($.eventName = "AttachUserPolicy") ||
    ($.eventName = "AttachRolePolicy") ||
    ($.eventName = "PutUserPolicy") ||
    ($.eventName = "PutRolePolicy") ||
    ($.eventName = "CreateLoginProfile") ||
    ($.eventName = "CreateSAMLProvider")
  }'

# Lambda en EventBridge events
aws logs filter-log-events \
  --log-group-name CloudTrail/management-events \
  --filter-pattern '{
    ($.eventName = "CreateFunction*") ||
    ($.eventName = "UpdateFunctionCode*") ||
    ($.eventName = "PutRule") ||
    ($.eventName = "PutTargets") ||
    ($.eventName = "AddPermission")
  }'

# Compute persistence events
aws logs filter-log-events \
  --log-group-name CloudTrail/management-events \
  --filter-pattern '{
    ($.eventName = "ModifyInstanceAttribute") ||
    ($.eventName = "CreateLaunchTemplateVersion") ||
    ($.eventName = "PutBucketNotificationConfiguration")
  }'

Azure AD Audit Logs

# Monitor app registrations en consent grants
az rest --method GET \
  --url "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDisplayName eq 'Add application' or activityDisplayName eq 'Consent to application' or activityDisplayName eq 'Add service principal credentials'&\$top=50" \
  | jq '.value[] | {activity: .activityDisplayName, time: .activityDateTime, actor: .initiatedBy.user.userPrincipalName}'

# Monitor role assignments
az rest --method GET \
  --url "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDisplayName eq 'Add member to role'&\$top=50" \
  | jq '.value[] | {time: .activityDateTime, actor: .initiatedBy.user.userPrincipalName, target: .targetResources[0].displayName}'

Access Key Rotation

# Forceer access key rotation met een maximum leeftijd
# Script: vind en rapporteer oude access keys
aws iam generate-credential-report
aws iam get-credential-report --query Content --output text | base64 -d | \
  awk -F',' 'NR>1 {
    if ($9 == "true" && $10 != "N/A") {
      split($10, a, "T");
      print "User: "$1, "Key 1 last rotated:", a[1]
    }
    if ($14 == "true" && $15 != "N/A") {
      split($15, a, "T");
      print "User: "$1, "Key 2 last rotated:", a[1]
    }
  }'

# Deactiveer keys ouder dan 90 dagen
for user in $(aws iam list-users --query 'Users[].UserName' --output text); do
  for key in $(aws iam list-access-keys --user-name "$user" --query 'AccessKeyMetadata[?Status==`Active`].AccessKeyId' --output text); do
    created=$(aws iam list-access-keys --user-name "$user" --query "AccessKeyMetadata[?AccessKeyId=='$key'].CreateDate" --output text)
    age=$(( ($(date +%s) - $(date -d "$created" +%s)) / 86400 ))
    if [ "$age" -gt 90 ]; then
      echo "ALERT: $user has key $key that is $age days old"
      # aws iam update-access-key --user-name "$user" --access-key-id "$key" --status Inactive
    fi
  done
done

Conditional Access

# Azure: Conditional Access policy die service principal access beperkt
az rest --method POST \
  --url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" \
  --body '{
    "displayName": "Restrict service principal locations",
    "state": "enabled",
    "conditions": {
      "clientApplications": {
        "includeServicePrincipals": ["All"]
      },
      "locations": {
        "includeLocations": ["All"],
        "excludeLocations": ["KNOWN_IP_RANGES"]
      }
    },
    "grantControls": {
      "operator": "OR",
      "builtInControls": ["block"]
    }
  }'

Referentietabel

Techniek MITRE ATT&CK AWS Azure GCP
Extra access keys T1098.001 - Additional Cloud Credentials iam:CreateAccessKey App credential addition Service account key creation
Backdoor IAM user/role T1136.003 - Cloud Account iam:CreateUser, iam:CreateRole az ad user create gcloud iam service-accounts create
Trust policy manipulation T1484.002 - Trust Modification iam:UpdateAssumeRolePolicy External identity providers Workload Identity pool trust
OAuth app registration T1098.003 - Additional Cloud Roles SAML/OIDC provider App Registration + consent OAuth2 client credentials
Compute startup scripts T1059 - Command and Scripting EC2 User Data VM Extensions GCE startup-script
Launch template poisoning T1525 - Implant Internal Image ec2:CreateLaunchTemplateVersion VMSS model update Instance template modification
Scheduled Lambda trigger T1053.007 - Container Orchestration Job EventBridge + Lambda Automation Runbooks Cloud Scheduler + Functions
Storage event trigger T1546 - Event Triggered Execution S3 notifications + Lambda Blob trigger + Function GCS notification + Function
DNS record manipulation T1584.002 - DNS Server Route53 record sets Azure DNS records Cloud DNS records
Subdomain takeover T1584.001 - Domains Dangling S3/EB CNAMEs Dangling Azure CNAMEs Dangling GCP CNAMEs
Golden SAML T1606.002 - SAML Tokens SAML IdP certificate theft ADFS signing cert theft SAML IdP compromise
Refresh token persistence T1550.001 - Application Access Token Cognito refresh tokens Azure AD refresh tokens Google OAuth refresh tokens
Lifecycle policy abuse T1053.007 - Container Orchestration Job S3 Lifecycle + notifications Blob lifecycle + triggers GCS lifecycle + notifications
Cross-account role backdoor T1098.003 - Additional Cloud Roles Cross-account trust policy Lighthouse delegation Cross-project SA impersonation
Automation runbook T1053.005 - Scheduled Task Lambda + EventBridge Automation Account + Runbook Cloud Scheduler job

De beste persistentie is de persistentie die er uitziet als een feature. En in de cloud is het verschil tussen een feature en een backdoor vaak niet meer dan de intentie van degene die het heeft geconfigureerd.

Op de hoogte blijven?

Ontvang maandelijks cybersecurity-inzichten in je inbox.

← Cloudbeveiliging ← Home