- Kubernetes API activity. Who called the cluster’s API server, what they did, and whether it succeeded.
- Cloud API activity. Changes to cloud resources and IAM in the account or project that hosts the environment.
What you collect
Ryvn already turns on control-plane logging when it provisions a cluster, but those logs stay next to the cluster in the provider’s default log store. The steps below copy them, along with the cloud API audit logs, into an archive that you control and that outlives the environment.
Before you start
Each example assumes a first-time setup for one environment, unused export resource names, and credentials with permission to create and configure the resources shown. Replace the example account, project, environment, and storage names with your own. Bucket and storage account names must be globally unique. These points apply to every provider:- Create the archive outside the environment. Use a bucket or storage account that Ryvn doesn’t manage, ideally in a dedicated security account, project, or resource group. Deleting the Ryvn environment then leaves the archive intact.
- Set retention, encryption, and access on the archive yourself. Pick the retention period your compliance program requires. Add object lock or immutable storage if you need tamper resistance.
- Set it up before you need the records. These exports don’t automatically backfill historical records. Configure them before the environment handles production traffic. Some providers offer separate exports of retained logs, such as the CloudWatch export described below.
- Expect some volume. Kubernetes audit logs include reads subject to the provider’s audit policy and configured exemptions. Read requests can generate substantial volume.
AWS
On AWS you set up two pipelines that both write to the same S3 bucket:- A CloudTrail trail for AWS management events.
- A CloudWatch Logs subscription that streams the EKS control-plane log group through Amazon Data Firehose to S3.
us-east-1, in the same AWS account, and creates a trail named ryvn-audit. Run the commands with credentials for that account.
Step 1: Find the cluster and its log group
Ryvn names EKS clustersryvn-eks-<environment-name>. Long environment names are shortened, so list the clusters to get the exact name:
api, audit, authenticator, controllerManager, and scheduler log types. EKS writes them to the CloudWatch log group /aws/eks/<cluster-name>/cluster. Confirm both:
Step 2: Prepare the S3 bucket
Create the archive bucket inus-east-1. S3 bucket creation in this region omits LocationConstraint:
Step 3: Turn on CloudTrail management events
If an existing account or organization trail already records read and write management events across all regions, including global service events, you can reuse it instead. Coordinate with its owner and verify its actual trail ARN, home region, and archive destination. The commands below assume a newryvn-audit trail.
CloudTrail needs permission to write to the bucket. Add these two statements to the bucket policy. If the bucket already has a policy, merge them into it, because put-bucket-policy replaces the whole policy.
cloudtrail-bucket-policy.json
BUCKET, REGION, and ACCOUNT_ID, then apply the policy and create the trail:
--kms-key-id and grant CloudTrail access in the key policy. See AWS’s KMS key policy for CloudTrail.
Step 4: Stream EKS logs to S3
CloudWatch Logs can’t write to S3 directly. A subscription filter sends new log events to a Firehose stream, and Firehose writes them to S3. You need two IAM roles, one for each hop. Check the log group’s existing subscriptions first. By default, AWS allows two subscription filters per log group.eks/ prefix of the bucket.
firehose-trust.json
firehose-s3.json
ACTIVE:
logs-trust.json
logs-firehose.json
kube-apiserver-audit-* and authenticator events from streams named authenticator-*. Each S3 object holds gzipped CloudWatch Logs batches that keep the logGroup, logStream, and event id of every record.
If the bucket uses a customer-managed KMS key, add "EncryptionConfiguration": {"KMSEncryptionConfig": {"AWSKMSKeyARN": "<key-arn>"}} to the Firehose destination and allow the Firehose role to use kms:GenerateDataKey and kms:Decrypt on the key.
Delivery timing
New logs should arrive undereks/ and cloudtrail/AWSLogs/ACCOUNT_ID/ in the archive bucket. This example configures Firehose with a five-minute buffering interval, and CloudTrail typically delivers events within about five minutes. Initial setup and source-log ingestion can add delay.
To recover EKS records from before you attached the subscription, run a one-off CloudWatch Logs export to S3 into a separate prefix. This only works for records still within the log group’s retention.
GCP
On GCP, Cloud Audit Logs already records Admin Activity for every service, including GKE, by default. You turn on Data Access logs for GKE, then create a log sink that copies the audit logs to a Cloud Storage bucket. This example keeps the archive in the same project as the cluster.Step 1: Find the cluster
Ryvn names GKE clustersryvn-gke-<environment-name>. List the clusters to get the exact name and location:
https://container.googleapis.com/v1/projects/PROJECT/locations/LOCATION/clusters/CLUSTER.
Use the location exactly as shown. A zonal cluster has a zone such as us-central1-a, and the sink filter in step 4 won’t match if you use the region instead.
Step 2: Turn on GKE Data Access audit logs
Admin Activity logs cover changes, such as creating a deployment. Kubernetes reads, such askubectl get secrets, are Data Access logs, and Google turns them off by default. Turn on all three Data Access types for the Kubernetes Engine API:
- In the Google Cloud console, open IAM & Admin > Audit Logs for the project.
- Select Kubernetes Engine API.
- Check Admin Read, Data Read, and Data Write, then click Save.
google_project_iam_audit_config with service = "container.googleapis.com". That resource is authoritative for the service, so import any existing configuration first.
Step 3: Prepare the Cloud Storage bucket
Create a bucket in the cluster’s project, outside the resources managed by Ryvn:Step 4: Create a log sink
Save this filter toaudit-filter.txt, replacing the three cluster values. It routes:
- All Admin Activity, System Event, and Policy Denied audit logs in the project.
- GKE management API Data Access logs, such as calls to describe the cluster.
- Kubernetes API Data Access logs for this cluster only.
audit-filter.txt
roles/logging.logWriter on that project instead. Keep the sink in the source project and the Object Creator grant on the archive bucket.
If your organization already has an aggregated sink at the folder or organization level, check whether it covers this project before adding another. Two sinks with overlapping filters write duplicate records.
Delivery timing
New matching logs should arrive in the archive bucket in folders such ascloudaudit.googleapis.com/activity and cloudaudit.googleapis.com/data_access. Cloud Storage receives logs in hourly batches, and the first files can take two to three hours to appear.
Azure
On Azure you add diagnostic settings that copy logs to a storage account:- One on the AKS cluster for Kubernetes audit logs.
- One on the subscription for the Activity Log.
- Optionally, one on the Entra ID tenant for sign-in and directory audit logs.
Microsoft.Storage/storageAccounts/listkeys/action on the storage account. Scope the second permission to the storage account only, because it exposes the account keys.
Creating the archive also requires permission to create the resource group and storage account; an authorized administrator can prepare these instead.
Step 1: Find the cluster
The standard Ryvn cluster name is<environment-name>-aks, in the resource group ryvn-rg-<environment-name>. Get its resource ID:
ryvn-control-plane-logs that sends control-plane and audit logs to a Log Analytics workspace in ryvn-rg-<environment-name>. Leave it in place. That workspace keeps logs for 30 days by default and is deleted with the environment, so it isn’t an archive. Azure allows five diagnostic settings per resource, so you can add your own alongside it.
Step 2: Prepare the storage account
Use a Standard general-purpose v2 storage account in the same region as the cluster. Put it in a resource group you own, not inryvn-rg-<environment-name>, which Ryvn deletes with the environment.
Step 3: Archive AKS audit logs
kube-audit, not kube-audit-admin. The admin category drops get and list requests, so you’d lose the record of who read what. The guard category records Entra ID authentication and Azure RBAC decisions for the cluster.
Step 4: Archive the subscription Activity Log
Step 5 (optional): Archive Entra ID logs
Kubernetes audit events show which identity made a request. Entra ID sign-in logs show how that identity got its token. A tenant administrator with the Security Administrator role sets this up once per tenant:- In the Microsoft Entra admin center, open Monitoring & health > Diagnostic settings and click Add diagnostic setting.
- Select the categories you need.
AuditLogscovers directory changes.SignInLogs,NonInteractiveUserSignInLogs,ServicePrincipalSignInLogs, andManagedIdentitySignInLogscover different kinds of callers. Some categories require an Entra ID P1 or P2 license. - Select Archive to a storage account, choose the storage account, and save.
Delivery timing
New logs should arrive in the storage account underinsights-logs-kube-audit, insights-logs-guard, and insights-activity-logs. Allow up to 90 minutes for a new diagnostic setting to begin delivery. Containers only appear after the first matching event. Optional Entra ID exports can take up to three days to begin delivery.
What these logs don’t cover
These steps collect control-plane and cloud API audit logs. They don’t collect:- Application logs from your services. See Logs.
- Network flow logs, DNS queries, or node operating system logs.
- Data-plane access to cloud services, such as individual S3 object reads or Azure Storage blob reads. Each service has its own logging for that.
- Commands typed inside a shell. A Kubernetes audit event for
kubectl execrecords the command used to start the session, but not what someone typed afterward.
Removing the export
When you retire an environment, remove the export for its cluster but keep the archive:- AWS. Delete the subscription filter, the Firehose stream, and the two IAM roles. Keep the trail if it covers other workloads in the account.
- GCP. Delete the sink if it only served this project, or update its filter if other clusters in the project still need it.
- Azure. Delete the
ryvn-audit-archivediagnostic setting on the cluster before you delete the environment. Azure doesn’t always remove diagnostic settings with their resource, and a cluster recreated with the same name would pick up the old setting. Remove the subscription and Entra ID settings only if nothing else in the subscription or tenant needs them.