/인프라/How to Fully Manage Kubernetes Secret Security Vulnerabilities with Vault and CSI Driver
Infrastructurek8s secrets managementvault k8s

How to Fully Manage Kubernetes Secret Security Vulnerabilities with Vault and CSI Driver

A practical guide to understanding the security limitations of native Kubernetes Secrets and building a Zero Trust secret-management architecture with HashiCorp Vault and the CSI Secrets Store Driver. It also covers dynamic secrets and auto

How to Fully Manage Kubernetes Secret Security Vulnerabilities with Vault and CSI Driver

Overcoming Kubernetes Secret Limitations: How to Perfectly Manage Sensitive Data with Vault and CSI

Kubernetes (K8s) is the core infrastructure of modern cloud-native environments. As countless applications are containerized and deployed, securely managing sensitive information (Secrets)—such as environment variables, API keys, and database connection details—has become one of the most critical security challenges.

Most development teams use the Secret resource by default. In production, however, relying on this built-in approach alone can leave you with serious security vulnerabilities. This guide examines the fundamental limitations of Kubernetes-native Secrets and provides a complete, practitioner-focused walkthrough of how to combine industry-standard HashiCorp Vault with the CSI Secrets Store Driver to build a secret-management architecture that aligns with Zero Trust principles.

Why Native Kubernetes Secrets Are Not Enough

The Kubernetes Secret resource is convenient, but it has fundamental design limitations. The biggest issues are how secrets are stored and the scope of access control.

  1. Lack of encryption (at the etcd level): By default, K8s Secrets are only Base64-encoded; strong encryption is not applied out of the box. If an attacker gains access to the cluster’s etcd database, they can easily steal secrets in plaintext (or in a form that is trivial to decode).
  2. Static management: Secrets are defined at deploy time. Updating them when they expire or change requires manual work, and dynamically refreshing them is difficult without complex custom logic.
  3. Overly broad access: When a secret is injected as a Pod environment variable, it remains exposed in memory for the lifetime of the Pod, which can violate the principle of least privilege.

To address these issues, we need to move secrets out of the cluster and into a dedicated, centralized security vault (Vault), fetching them only temporarily when they are actually needed.

🛡️ Security Comparison: Native Secrets vs. Vault Integration

FeatureNative K8s SecretVault + CSI DriverSecurity Level
Storage locationK8s etcd (inside the cluster)Dedicated external Vault serverHigh
EncryptionBase64 encoding (weak)Strong encryption (Transit/Storage Backend)Very high
Access controlRBAC-based (cluster level)Vault policy-based (application/service level)Very high
Secret lifetimeStatic (fixed at deploy time)Dynamic (on-demand, auto-renewable)Very high
Zero Trust fitLowHigh (access only when needed)Highest

🚀 Understanding the Architecture with Vault and CSI Driver

The core of this system is the CSI Secrets Store Driver. When Kubernetes says “I need this secret,” the driver does not fetch the secret value itself. Instead, at the container runtime level, it handles the request as “Please retrieve this secret from Vault.”

[Understanding the system architecture]

  1. Application Pod: Declares that it needs a secret.
  2. K8s API Server: Reads the SecretProviderClass and forwards the secret request to the CSI Driver.
  3. CSI Driver: Receives the request and authenticates to Vault using a preconfigured mechanism (for example, a Kubernetes Service Account Token).
  4. Vault: Validates the request, retrieves the secret required by that Pod, and returns it to the CSI Driver.
  5. CSI Driver: Mounts the received secret into a Pod volume so the application can access it as if it were a local file.

With this design, secret values are never stored in K8s etcd. When the Pod terminates, the secret disappears from the volume, maximizing security.

🛠️ Hands-on Guide: A 3-Step Implementation for Vault Integration

Here is a step-by-step guide for applying this in a real production environment. We assume Vault is already deployed stably outside the cluster or in a separate namespace.

Step 1: Configure Vault Authentication and Authorization (Vault side)

First, you must configure how the Kubernetes cluster proves its identity to Vault. The most common and secure approach is the Kubernetes Auth Method.

Enable the Kubernetes auth method in Vault and define a policy that allows access only from specific namespaces and Service Accounts.

Bash
# 예시: Vault에 K8s Auth Method 활성화 및 정책 바인딩
vault write auth/kubernetes/config \
    kubernetes_enabled=true \
    kubernetes_host=<YOUR_K8S_API_SERVER> \
    kubernetes_namespace="default"

Step 2: Deploy the CSI Driver and SecretProviderClass (K8s side)

Install the CSI Driver in the cluster and create a SecretProviderClass that defines which secrets to fetch. This YAML file is the key piece.

secret-provider-class-example.yaml

YAML
apiVersion: kyverno.io/v1
kind: SecretProviderClass
metadata:
  name: vault-db-credentials
  namespace: default
spec:
  provider: vault
  parameters:
    vault:
      address: "http://vault.vault.svc:8200" # Vault 서비스 주소
      role: "k8s-service-role" # 1단계에서 정의한 Vault Role
      secretPath: "database/creds/myapp" # Vault 내의 시크릿 경로
      key: "username" # 가져올 첫 번째 키
      key: "password" # 가져올 두 번째 키

Practical tip: Defining key multiple times as in the example above is not valid YAML; in practice you should use a parameters map in the form key1: value1, key2: value2. The important point is that this YAML leaves only the metadata—“which secret is needed”—in Kubernetes; the actual values live in Vault.

Step 3: Deploy the Pod and Mount the Volume

When you deploy the application Pod, use a volume that references this SecretProviderClass instead of environment variables.

YAML
apiVersion: v1
kind: Pod
metadata:
  name: app-with-vault-secret
spec:
  containers:
  - name: my-app
    image: my-backend-image:latest
    volumeMounts:
    - name: vault-secrets
      mountPath: "/mnt/secrets" # 컨테이너 내부에서 접근할 경로
  volumes:
  - name: vault-secrets
    csi:
      driver: secrets-store.csi.open-source.com # CSI Driver 지정
      secretProviderClass:
        name: vault-db-credentials # 2단계에서 정의한 클래스 참조

When the Pod starts, the CSI Driver automatically contacts Vault, retrieves the secrets, and mounts them as files under /mnt/secrets. The application then reads the connection details from this mounted filesystem.

🛡️ Production-Grade Hardening: Automatic Rotation and Auditing

Storing secrets securely is not enough; you also need to harden security at the operational level.

1. Automatic Secret Rotation (Dynamic Secrets)

This is the most powerful security feature. Instead of hardcoding database passwords, use Vault’s Dynamic Secrets Engine. When the application requests “I need DB credentials,” Vault connects to the database, creates an ephemeral username and password, and automatically expires or revokes them after a set period (for example, 1 hour).

Even if a password leaks, its lifetime is very short, so the window an attacker can exploit is extremely limited.

2. Audit Logging and Monitoring

Every access attempt must be recorded. Vault provides audit logs that capture every API call in detail (who accessed which secret, and when). Forward these logs to a centralized logging system (such as the ELK Stack) and monitor in real time for abnormal patterns (for example, a large number of secret lookups in the middle of the night).

💡 A practitioner’s take from a developer’s perspective: In real production environments I strongly avoid injecting secrets as environment variables. Environment variables can be exposed via the process list (ps -ef). Mounting via CSI volumes is the safest approach, and I am convinced that reading values through file I/O at the application-code level is the most robust pattern.

Frequently Asked Questions (FAQ)

Q1. Does using the CSI Driver cause significant performance degradation? A. There can be network latency during the initial connection and secret loading. Once the volume is mounted, however, the application accesses secrets at nearly the same speed as reading from the local filesystem. Performance issues mainly occur during initialization, so minimizing load time is important.

Q2. Which token should I use when authenticating Vault with Kubernetes? A. Typically you use a Kubernetes Service Account Token. The K8s API server issues this token, and Vault verifies the issuer and claims to confirm that the Pod is a legitimate service.

Q3. How should the application behave when a secret expires? A. Application code should wrap secret reads in a try-catch block, detect file-access failures (for example, "No such file or directory"), and either implement retry logic or raise an alert to operators.

Conclusion: Next Steps Toward a Secure Infrastructure

In Kubernetes, secret management is no longer an add-on—it is a foundation of the infrastructure. Rather than settling for the convenience of native Secrets, adopt specialized tools like Vault and the CSI Driver to centralize secrets and take advantage of dynamic generation and strong auditing. That is the standard for a modern security architecture.

With the architecture you learned today, your cluster can evolve from a simple deployment environment into a trustworthy platform with top-tier security. I strongly recommend defining a SecretProviderClass in a test environment right now and practicing isolating sensitive data safely.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.