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
doneConditional 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.
Verder lezen in de kennisbank
Deze artikelen in het portaal geven je meer achtergrond en praktische context:
- De cloud — andermans computer, jouw verantwoordelijkheid
- Containers en Docker — wat het is en waarom je het moet beveiligen
- Encryptie — de kunst van het onleesbaar maken
- Least Privilege — geef mensen alleen wat ze nodig hebben
Je hebt een account nodig om de kennisbank te openen. Inloggen of registreren.
Gerelateerde securitymaatregelen
Deze artikelen bieden aanvullende context en verdieping: