Velero holds a cluster-wide view of your Kubernetes objects, a set of cloud storage credentials and a copy of every Secret it backs up, so whoever controls Velero or its bucket effectively controls a second copy of the cluster. This guide covers the customer side of running Velero securely: the Kubernetes permissions its service account needs, the credentials it uses to reach object storage and snapshot APIs, how backup data is encrypted, who can create backups and restores, and what to watch. It is written for platform engineers, SREs and security reviewers who own Velero in production clusters. For backup strategy, recovery objectives and restore testing across tools, see the Kubernetes Backup and Recovery guide; this page goes deeper on Velero itself.
This is an independent guide from NHI Mgmt Group, based on Velero's public documentation as of November 2026. It is not sponsored or reviewed by the Velero project. Product features change, so confirm settings against Velero's current documentation for the version you run.
Key takeaways
- Scope down the cluster-admin default. Velero installs bound to the cluster-admin ClusterRole; the project documents a narrower ClusterRole with list on all resources, full verbs only on namespaces and persistentvolumes, and get on customresourcedefinitions.
- Treat the bucket as the crown jewels. Backups include Secrets, ServiceAccounts and RBAC objects, and Velero relies on the object store's own encryption for backup metadata, so bucket access equals access to cluster secrets.
- Give each location its own narrow credential. By default every BackupStorageLocation and VolumeSnapshotLocation shares the cloud-credentials secret; use the per-location credential field and a bucket dedicated to one cluster.
- Set your own repository password before the first backup. File System Backup with Kopia uses a common key held in velero-repo-credentials; change the repository-password key before any repository is created.
- Control who can restore. Creating a Restore object can recreate ClusterRoles, bindings and Secrets in a live cluster, so limit write access to velero.io resources and use ReadOnly access mode for locations used only for recovery.
How identity and access work in Velero
Velero has no user login of its own. Every action, from the velero CLI or from GitOps tooling, is a Kubernetes custom resource (Backup, Restore, Schedule, BackupStorageLocation, VolumeSnapshotLocation and others in the velero.io API group) that the Velero server reconciles using its own service account. That gives Velero three identity layers, and each needs its own control.
| Layer | Identity | What it can reach | Customer control |
|---|---|---|---|
| Operators and automation | Kubernetes users and groups with RBAC on velero.io resources | Create, delete and restore backups by writing custom resources | Namespace-scoped Roles on velero.io; separate "backup" and "restore" rights |
| Velero server and node agent | The velero ServiceAccount in the install namespace | Read all objects it backs up; create objects during restore | Replace cluster-admin with the documented narrower ClusterRole |
| Storage and snapshot plugins | Cloud credential in cloud-credentials or a per-location secret, or a pod identity | The backup bucket and the provider snapshot API | Least-privilege cloud policy, one bucket per cluster, workload identity where the plugin supports it |
The practical point: a person who can create a Backup object can make Velero read Secrets they could not read directly, and a person who can create a Restore can make Velero write objects they could not write directly. Velero is a privileged proxy, so RBAC on its custom resources matters as much as RBAC on Secrets. See the Kubernetes RBAC Guide for the underlying model.
Admin roles and privileged access
The Velero service account
Velero's RBAC documentation states that, by default, Velero runs with the cluster-admin ClusterRole and recommends restricting it to suit your environment. The documented narrower ClusterRole (velero-clusterrole in the sample) grants:
- namespaces, all verbs: needed to create namespaces during restore. If you never restore into new namespaces, remove create; get and list stay so Velero can check whether a namespace exists.
- persistentvolumes, all verbs: needed for volume backup and restore. Remove the rule if you do not back up volumes.
- customresourcedefinitions, get: needed to back up the CRDs behind custom resources. The docs advise keeping it.
- list on all resources in all API groups: Velero reads objects it does not back up directly, such as ClusterRoles when it backs up ServiceAccounts and VolumeSnapshotContent for CSI volumes. The docs warn that narrowing list too far can make backups or restores fail.
Where Velero only protects one namespace, the documented namespace-scoped sample uses a Role with all verbs on velero.io resources in that namespace plus a RoleBinding to the Velero service account. Test the narrowed role with a full backup and a restore into a scratch cluster before you remove cluster-admin, and keep the old binding manifest so you can roll back.
Human operators
- Backup operators: create and get on backups and schedules in the Velero namespace. Our recommendation at NHI Mgmt Group is to give most platform engineers this and nothing more.
- Restore operators: create on restores. Keep this to a small break-glass group, because a restore can recreate ClusterRoleBindings and Secrets from any backup the location holds.
- Location administrators: create, update and delete on backupstoragelocations and volumesnapshotlocations, plus read on the credential secrets. Treat this as cluster-admin equivalent: whoever can point Velero at a new bucket can export the whole cluster.
- Deletion: backup deletion requests (confirm the resource name in the Velero documentation for your release) remove backup data from storage. Limit delete rights and pair them with bucket-side retention (see the hardening baseline).
Restore behaviour to plan for
Velero's restore reference describes the default restore as non-destructive: existing resources are skipped, not overwritten. ServiceAccounts are the documented exception, where Secrets and imagePullSecrets from the backup are appended to the existing account and missing labels and annotations are added. The --existing-resource-policy update option patches live objects to match the backup and should be used deliberately. Default restore order includes ClusterRoles, Roles, ServiceAccounts, ClusterRoleBindings, RoleBindings and Secrets, so a restore from an old or tampered backup can bring back access you removed. Review the contents of a backup with velero backup describe --details before restoring it into production, and use --namespace-mappings to restore into an isolated namespace first when in doubt.
Integrations, API tokens and service accounts
Storage and snapshot credentials
Velero's locations documentation says BackupStorageLocations and VolumeSnapshotLocations use the cloud-credentials secret in the Velero namespace unless told otherwise. Editing that secret affects every location using it, which helps rotation but also widens blast radius. Each location can reference its own secret with --credential=<secret-name>=<key> on velero backup-location create or set (and the snapshot-location equivalents), stored in the credential field of the resource. All plugins maintained by the Velero team support per-location credentials.
| Option | How it is configured | When to use it |
|---|---|---|
| Static key in cloud-credentials | --secret-file at install; one secret for all locations | Labs and single-location clusters only; rotate on a schedule |
| Per-location secret | credential/name and credential/key on each location | Several buckets or accounts, for example a separate recovery bucket |
| Pod identity, no secret | --no-secret plus pod annotations or service account binding for your provider's workload identity | Production, where the plugin documents it; removes long-lived keys from the cluster |
The AWS plugin documents a minimal IAM policy: ec2:DescribeVolumes, ec2:DescribeSnapshots, ec2:CreateTags, ec2:CreateVolume, ec2:CreateSnapshot and ec2:DeleteSnapshot on snapshots; s3:GetObject, s3:PutObject, s3:DeleteObject, s3:AbortMultipartUpload and s3:ListMultipartUploadParts on the bucket's objects; s3:ListBucket on the bucket itself; s3:PutObjectTagging only if you use config.tagging. It also documents installing with --no-secret and a pod role annotation, and notes that pod-based authentication applies one identity to all locations, so additional locations with different credentials need secrets. Confirm the current options for your provider in its plugin documentation. For the identity pattern, see the Workload Identity Federation Guide.
Encryption of backup data
- Object store encryption: Velero relies on the native encryption of the object store and snapshot system for backup metadata and volume snapshots. Turn on bucket default encryption. The AWS plugin documents kmsKeyId for SSE-KMS (which supports KMS key rotation), customerKeyEncryptionFile or customerKeyEncryptionSecret for SSE-C, and ebsKmsKeyId for encrypting restored volumes.
- File System Backup (Kopia): the File System Backup page states that Velero uses a static, common encryption key for all backup repositories it creates, held as the repository-password key in the velero-repo-credentials secret. Set your own value before the first backup to a repository: changing it later means Velero cannot connect to older backups. Store the password in your secrets manager as well, because a rebuilt cluster needs it to read old backups.
- TLS to storage: for private S3-compatible endpoints, supply a CA bundle with objectStorage/caCertRef (a Secret reference; the inline caCert field is deprecated) rather than disabling verification.
See the Kubernetes Secrets Security Guide for protecting the secrets Velero both holds and copies.
Node agent and hooks
- node-agent DaemonSet: File System Backup reads volume data through a hostPath mount of /var/lib/kubelet/pods, runs as root and, in some environments, privileged (on OpenShift it needs the privileged SCC and --privileged-node-agent). Enable it only where you need file-level volume backup, exempt only the Velero namespace from your admission policy, and set resource limits, since the docs note BestEffort QoS by default.
- Backup hooks: annotations such as pre.hook.backup.velero.io/command and post.hook.backup.velero.io/command make Velero execute a command in a pod's container (the first container if pre.hook.backup.velero.io/container is unset). Anyone who can annotate pods can request command execution at backup time, so control pod patch rights and restrict hooks with admission policy to the workloads that need them.
Logging and detection
| Source | What to watch | Why |
|---|---|---|
| Kubernetes audit log | create, update and delete on backupstoragelocations, volumesnapshotlocations, restores and backup deletion requests; get on cloud-credentials, velero-repo-credentials and per-location secrets | New locations and unexpected restores are the main abuse paths |
| Velero resources | BSL phase (validated every minute by default via validationFrequency); backup status Completed, PartiallyFailed or Failed; HooksAttempted and HooksFailed in velero backup describe | Silent backup failure and tampered hooks |
| Cloud audit and storage logs | Object reads and deletes on the backup bucket from anything other than the Velero identity; policy and encryption changes on the bucket and key | Exfiltration of backup data (ATT&CK T1530) and recovery sabotage (T1490) |
| Restored objects | Labels velero.io/backup-name and velero.io/restore-name on live objects | Trace which restore created a ClusterRoleBinding or Secret |
| Velero server metrics | Backup success and failure counts per schedule, where your deployment exposes Velero metrics (confirm in the Velero documentation) | Alert on missed or failed schedules |
Route these to the same pipeline as cluster audit events. The Kubernetes Audit Log Detection Guide covers the audit policy needed to capture secret reads.
Metrics that show it is working:
- Percentage of clusters where Velero is bound to a scoped ClusterRole rather than cluster-admin.
- Number of long-lived storage keys in Velero namespaces (target zero where workload identity is available), and age of any that remain.
- Scheduled backup success rate over 30 days, and time since the last successful test restore.
- Count of identities with create on restores or backupstoragelocations, reviewed quarterly.
- Bucket access events from principals other than Velero (target zero outside approved recovery).
Hardening baseline
- Inventory first. List every cluster running Velero, its version, its locations and the identity each location uses. Apply Velero releases and plugin updates promptly and follow the project's release notes.
- Dedicate storage. The docs say Velero takes control of a location and recommend a dedicated bucket or prefix; our recommendation is one bucket per cluster, in a separate cloud account or project from the cluster where possible. See the Backup Identity Isolation Guide.
- Protect the bucket. Default encryption with a customer-managed key, versioning and object lock or retention locks so a stolen Velero credential cannot erase history. See the Backup Security and Immutable Backup Guide.
- Replace static keys. Move to pod identity with --no-secret where your plugin supports it; otherwise use per-location secrets, rotated on a schedule (ours: 90 days or on staff change).
- Scope RBAC. Swap cluster-admin for the documented ClusterRole, remove verbs you do not use, and split backup, restore and location rights between groups.
- Set the repository password in velero-repo-credentials before enabling File System Backup, and escrow it.
- Use ReadOnly for recovery. Set accessMode: ReadOnly on locations that a recovery or DR cluster reads from, so that cluster cannot write or delete backups.
- Test restores into an isolated cluster on a schedule, check the result for PartiallyFailed status and hook errors, and roll back a failed change by reapplying the previous manifests.
Common misconfigurations
- Leaving cluster-admin in place. The default binding is convenient and often never revisited. Scope it once the first restore test passes.
- One shared bucket for many clusters. A single credential then reads every cluster's Secrets, and a mistaken location can sync another cluster's backups. Keep one bucket or prefix per cluster.
- Keeping the default repository password. Because it is a common default, anyone with bucket access and Velero knowledge can read File System Backup data. Set it before first use.
- Granting restore rights broadly. Restores recreate RBAC and Secrets, and ServiceAccounts are merged rather than skipped. Keep restore with a small group and review backups before restoring.
- Bucket deletion rights without retention. Velero needs s3:DeleteObject to expire backups, so pair it with versioning and object lock to keep a recovery point the credential cannot remove.
- Unrestricted hook annotations. Any team that can patch pods can run commands at backup time. Allow hooks only where an admission policy permits them.
Framework mapping
| Control area | NIST SP 800-53 Rev 5 | NIST CSF 2.0 | CIS Controls v8.1 | ISO/IEC 27001:2022 Annex A |
|---|---|---|---|---|
| Backup protection and restore testing | CP-9, CP-10 | PR.DS-11 | Control 11 Data Recovery | A.8.13 Information backup |
| Velero and operator least privilege | AC-6 | PR.AA-05 | Control 6 Access Control Management | A.8.2 Privileged access rights |
| Encryption and key handling | SC-28, SC-12 | PR.DS-11 | Control 3 Data Protection | A.8.24 Use of cryptography |
| Storage credentials | IA-5 | PR.AA-05 | Control 5 Account Management | A.5.17 Authentication information |
| Monitoring backup and restore activity | AU-2, AU-6 | DE.CM-09 | Control 8 Audit Log Management | A.8.15 Logging |
Relevant ATT&CK techniques: T1530 Data from Cloud Storage (backup exfiltration), T1490 Inhibit System Recovery (deleting backups before an attack) and T1552.007 Container API (harvesting credentials through the Kubernetes API).
Practitioner checklist
- Replace the cluster-admin binding with the documented scoped ClusterRole and remove unused verbs.
- Split RBAC on velero.io resources into backup, restore and location administration groups.
- Use one dedicated bucket or prefix per cluster, encrypted with a customer-managed key, with versioning and retention locks.
- Move storage access to pod identity with --no-secret where supported, or per-location secrets with scheduled rotation.
- Set repository-password in velero-repo-credentials before the first File System Backup and escrow it.
- Set accessMode: ReadOnly on locations read by recovery clusters.
- Supply caCertRef for private endpoints instead of disabling TLS checks.
- Limit the privileged node-agent and hook annotations to the namespaces that need them.
- Alert on location changes, restores, secret reads and non-Velero bucket access.
- Run a scheduled restore test into an isolated cluster and review backup contents before production restores.
Standards and references
- Velero: Run Velero more securely with restrictive RBAC settings
- Velero: Backup Storage Locations and Volume Snapshot Locations
- Velero: BackupStorageLocation API type
- Velero: File System Backup
- Velero: Restore Reference
- Velero: Backup Hooks
- Velero: Plugin for AWS (IAM and encryption setup)
- NIST: SP 800-53 Rev 5 Security and Privacy Controls
Related NHI Mgmt Group resources: Kubernetes Backup and Recovery · Kubernetes Secrets Security Guide · Cloud Native Backup and Ransomware Resilience Guide · Kubernetes NHI Security Guide