Using Sealed Secrets for Secure GitOps Deployments

Overview

Managing secrets securely in a GitOps workflow is a critical challenge. Storing plain Kubernetes secrets in a Git repository is risky because anyone with access to the repository can view them. Sealed Secrets, an open-source project by Bitnami, provides a way to encrypt secrets before storing them in Git, ensuring they remain secure.

Key Takeaways:

  • Securely store Kubernetes secrets in a Git repository.
  • Automate secret management using GitOps principles.
  • Ensure secrets can only be decrypted by the Kubernetes cluster.

Step 1: Install Sealed Secrets Controller

The Sealed Secrets Controller runs in the Kubernetes cluster and is responsible for decrypting Sealed Secrets into regular Kubernetes secrets.

Install via Helm

helm repo add bitnami https://charts.bitnami.com/bitnami
helm install sealed-secrets bitnami/sealed-secrets --namespace kube-system

Verify installation:

kubectl get pods -n kube-system | grep sealed-secrets
kubectl get svc -n kube-system | grep sealed-secrets

Step 2: Install Kubeseal CLI

To encrypt secrets locally before committing them to Git, install the kubeseal CLI:

Linux Installation

wget https://github.com/bitnami-labs/sealed-secrets/releases/latest/download/kubeseal-linux-amd64 -O kubeseal
chmod +x kubeseal
sudo mv kubeseal /usr/local/bin/Overview

Verify installation:

kubeseal --version

Step 3: Create a Kubernetes Secret

Let’s create a secret for a database password.

Create a file named secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
  namespace: default
type: Opaque
data:
  DB_PASSWORD: cGFzc3dvcmQ=   # Base64 encoded "password"
Click Here to View & Copy YAML

Apply the secret:

kubectl apply -f secret.yaml

Step 4: Encrypt the Secret Using Kubeseal

Use the kubeseal CLI to encrypt the secret so it can be safely stored in Git.

kubeseal --controller-name=sealed-secrets \
  --controller-namespace=kube-system \
  --format=yaml < secret.yaml > sealed-secret.yaml

The output sealed-secret.yaml will contain an encrypted version of the secret.

Example:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: my-secret
  namespace: default
spec:
  encryptedData:
    DB_PASSWORD: AgA+...long_encrypted_value...==
Click Here to View & Copy YAML

Now, delete the original secret from the cluster:

kubectl delete secret my-secret

Step 5: Apply Sealed Secret to Kubernetes

Deploy the sealed secret to Kubernetes:

kubectl apply -f sealed-secret.yaml

The Sealed Secrets Controller will automatically decrypt it and create a regular Kubernetes secret.

Verify the secret is recreated:

kubectl get secrets

Step 6: Push to GitHub for GitOps

Now, let’s commit the sealed secret to GitHub so it can be managed in a GitOps workflow.

Initialize a Git Repository (If Not Already Done)

git init
git remote add origin https://github.com/ArvindRaja45/deploy.git

Add and Commit Sealed Secret

git add sealed-secret.yaml
git commit -m "Added sealed secret for GitOps"
git push origin main

Step 7: Automate Deployment with GitHub Actions

To deploy the sealed secret automatically, create a GitHub Actions workflow.

Create a new file: .github/workflows/deployment.yaml

Push the Workflow to GitHubname: Deploy Sealed Secret

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up kubectl
        uses: azure/setup-kubectl@v3
        with:
          version: 'latest'

      - name: Configure Kubeconfig
        run: echo "$KUBECONFIG_DATA" | base64 --decode > kubeconfig.yaml

      - name: Deploy Sealed Secret
        run: kubectl apply -f sealed-secret.yaml --kubeconfig=kubeconfig.yaml
Click Here to View & Copy YAML

Push the Workflow to GitHub

git add .github/workflows/deployment.yaml
git commit -m "Added GitHub Actions deployment workflow"
git push origin main

Conclusion

Using Sealed Secrets, we achieved:

  • Secure secret management in GitOps workflows.
  • Automated deployments with GitHub Actions.
  • No plaintext secrets in Git repositories.

This setup ensures that secrets remain encrypted at rest, providing a secure and automated way to manage secrets in a Kubernetes environment.

Have you used Sealed Secrets in your GitOps workflow? Share your experience!👇

Automating Kubernetes Deployments with GitHub Actions

In today’s DevOps world, automation is key to faster and more reliable deployments. Instead of manually applying Kubernetes manifests, we can use GitHub Actions to trigger deployments automatically whenever we push code.

What We Built Today?

  • A complete GitHub Actions pipeline for Kubernetes deployments
  • End-to-end automation from code commit to deployment
  • Secure & efficient setup using GitHub Secrets

Key Challenges We Solved:

  • How to integrate GitHub Actions with Kubernetes?
  • Ensuring deployments are non-root and secure
  • Handling GitHub Secrets for secure kubeconfig access Kubernetes Deployment YAML

Here’s the Kubernetes deployment we used today:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      securityContext:
        runAsNonRoot: true
      containers:
        - name: myapp
          image: nginxinc/nginx-unprivileged:latest
          ports:
            - containerPort: 80
          securityContext:
            runAsNonRoot: true
            readOnlyRootFilesystem: true
          volumeMounts:
            - mountPath: /var/cache/nginx
              name: cache-volume
            - mountPath: /tmp
              name: tmp-volume
      volumes:
        - name: cache-volume
          emptyDir: {}
        - name: tmp-volume
          emptyDir: {}
Click Here to Copy YAML
  • Runs as a non-root user
  • Read-only root filesystem for security
  • Uses nginx-unprivileged for better compliance Setting Up GitHub Actions for Kubernetes

To automate deployment, we used this GitHub Actions workflow:

name: Deploy to Kubernetes

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Set up kubectl
        uses: azure/setup-kubectl@v3
        with:
          version: latest

      - name: Configure Kubernetes Cluster
        run: |
          echo "${{ secrets.KUBECONFIG }}" | base64 --decode > kubeconfig
          export KUBECONFIG=kubeconfig

      - name: Deploy to Kubernetes
        run: kubectl apply -f deploy.yaml
Click Here to Copy YAML

What It Does?

  • Triggers on every git push to main
  • Sets up kubectl to interact with the cluster
  • Uses GitHub Secrets (KUBECONFIG) for secure authentication
  • Deploys the latest changes to Kubernetes automatically

Why This Matters?

  • No more manual deployments
  • Instant updates on every push
  • Security-first approach with GitHub Secrets

Do you automate your Kubernetes deployments? Let’s discuss best practices in the comments! 👇

Implementing GitOps with Flux CD: A Deep Dive into Automated Kubernetes Deployments

The Challenge:

Ensuring a declarative and automated synchronization between Git and Kubernetes clusters is crucial for consistency, version control, and automated rollback capabilities. Traditional CI/CD pipelines often introduce inconsistencies due to manual triggers and state drift.

The Solution: Flux CD

Flux CD follows the GitOps model, ensuring that the desired state defined in a Git repository is continuously reconciled with the actual state in Kubernetes.

Example Scenario:

We are deploying a secure Nginx application using Flux CD. The goal is to:

  • Automate deployments from a private Git repository
  • Ensure rollback capabilities with Git versioning
  • Enforce a secure and immutable infrastructure

Step 1: Install Flux CLI

Ensure you have kubectl and helm installed, then install the Flux CLI:

curl -s https://fluxcd.io/install.sh | sudo bash
export PATH=$PATH:/usr/local/bin
flux --version

Step 2: Bootstrap Flux in Your Kubernetes Cluster

Flux needs to be bootstrapped with a Git repository that will act as the single source of truth for deployments.

flux bootstrap github \
  --owner=<your-github-username> \
  --repository=flux-gitops \
  --branch=main \
  --path=clusters/my-cluster \
  --personal

This command:

  • Sets up Flux in the cluster
  • Connects it to the specified GitHub repository
  • Deploys Flux components

Step 3: Define a GitOps Repository Structure

Structure your repository as follows:

flux-gitops/
│── clusters/
│   ├── my-cluster/
│   │   ├── kustomization.yaml
│── apps/
│   ├── nginx/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   ├── kustomization.yaml

Step 4: Deploy a Secure Nginx Application

apps/nginx/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-secure
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-secure
  template:
    metadata:
      labels:
        app: nginx-secure
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.6
        ports:
        - containerPort: 80
        securityContext:
          runAsNonRoot: true
          readOnlyRootFilesystem: true
Click Here to Copy YAML

apps/nginx/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: default
spec:
  selector:
    app: nginx-secure
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
Click Here to Copy YAML

Step 5: Register the Nginx Application with Flux

Flux requires a Kustomization resource to track and deploy applications.

apps/nginx/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
  name: nginx
  namespace: flux-system
spec:
  targetNamespace: default
  interval: 1m
  sourceRef:
    kind: GitRepository
    name: flux-gitops
  path: "./apps/nginx"
  prune: true
  wait: true
Click Here to Copy YAML

Apply the Kustomization to the cluster:

kubectl apply -f apps/nginx/kustomization.yaml

Flux will now continuously monitor and apply the Nginx manifests from the Git repository.

Step 6: Verify Deployment

Check the status of the Nginx deployment:

kubectl get pods -l app=nginx-secure
kubectl get svc nginx-service

Flux’s reconciliation logs can be checked with:

flux get kustomizations
flux get sources git

Step 7: Automatic Rollback

Flux tracks all changes via Git. If an incorrect version of Nginx is deployed, revert using:

git revert <commit-id>
git push origin main

Flux will detect this change and automatically restore the last stable state.

Flux CD ensures:

  • Continuous deployment from Git
  • Automated rollbacks via Git versioning
  • Enhanced security with read-only containers
  • Immutable and declarative infrastructure

This is how GitOps transforms Kubernetes deployments into a fully automated and scalable process.

Conclusion

GitOps with Flux CD revolutionizes Kubernetes deployments by making them declarative, automated, and highly secure. With Git as the single source of truth, deployments become version-controlled, reproducible, and rollback-friendly.

Are you using GitOps in production? Drop a comment!👇

Setting Up Tekton Pipelines for Kubernetes-Native CI/CD

Why Tekton?

In modern cloud environments, traditional CI/CD tools can introduce complexity and infrastructure overhead. Tekton, a Kubernetes-native CI/CD framework, provides:

  • Declarative Pipelines with Kubernetes CRDs
  • Event-Driven Automation through triggers
  • Seamless GitHub & DockerHub Integration
  • Scalability & Portability across Kubernetes clusters

With Tekton, CI/CD becomes a native Kubernetes workload, reducing external dependencies and enhancing automation.

Real-World Use Case

Imagine a microservices-based application where developers frequently push updates to GitHub. A robust pipeline is required to:

  • Detect changes in the repository
  • Build & test the application
  • Push the container image to a registry
  • Deploy the latest version to Kubernetes automatically

Tekton enables this entire process within Kubernetes—without relying on external CI/CD systems.

Step 1: Install Tekton in Kubernetes

1.1 Install Tekton Pipelines

kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml

1.2 Install Tekton Triggers

kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml

1.3 Verify Installation

kubectl get pods -n tekton-pipelines

Step 2: Define Tekton Pipeline Components

2.1 Create a Tekton Task (task-build.yaml)

This task clones a GitHub repository and builds a container image using Kaniko.

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: build-task
spec:
  steps:
    - name: clone-repo
      image: alpine/git
      script: |
        #!/bin/sh
        git clone https://github.com/ArvindRaja45/rep.git /workspace/source
    - name: build-image
      image: gcr.io/kaniko-project/executor:latest
      args:
        - "--context=/workspace/source"
        - "--destination=myrepo/my-app:latest"
Click Here to Copy YAML

2.2 Apply the Task

kubectl apply -f task-build.yaml

Step 3: Define the Pipeline (pipeline.yaml)

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: ci-pipeline
spec:
  tasks:
    - name: build
      taskRef:
        name: build-task
Click Here to Copy YAML
kubectl apply -f pipeline.yaml

Step 4: Configure PipelineRun (pipelinerun.yaml)

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: ci-pipeline-run
spec:
  pipelineRef:
    name: ci-pipeline
Click Here to Copy YAML
kubectl apply -f pipelinerun.yaml

Step 5: Automate Triggering with Tekton Triggers

5.1 Define an EventListener

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: github-listener
spec:
  serviceAccountName: tekton-triggers-sa
  triggers:
    - name: github-push
      bindings:
        - ref: github-trigger-binding
      template:
        ref: github-trigger-template
Click Here to Copy YAML
kubectl apply -f eventlistener.yaml

5.2 Expose the Listener

kubectl port-forward service/el-github-listener 8080:8080 -n tekton-pipelines

Step 6: Connect to GitHub Webhooks

  • Go to GitHub → Repository → Settings → Webhooks
  • Add http://EXTERNAL_IP:8080
  • Select application/json and push event

Step 7: Monitor the Pipeline Execution

tkn pipeline list
tkn pipelinerun list
tkn pipelinerun describe ci-pipeline-run

Key Takeaways

  • Kubernetes-native automation simplifies CI/CD workflows
  • Event-driven pipelines improve efficiency and response time
  • GitOps integration ensures seamless deployment processes
  • Scalability—Tekton adapts to both small and large-scale applications

Conclusion

Now you have a fully Kubernetes-native CI/CD pipeline using Tekton, with automated GitHub-triggered builds and deployments.

Want to go deeper? Let’s explore multi-stage pipelines, security scans, and GitOps integrations! Drop a comment👇

Zero-Downtime Deployments with ArgoCD in Minikube – A Game Changer!

The Challenge

Ever pushed an update to your Kubernetes app and suddenly… Downtime!
Users frustrated, services unavailable, and rollback becomes a nightmare. Sounds familiar?

The Solution: GitOps + ArgoCD

With ArgoCD, we eliminate downtime, automate rollbacks, and ensure seamless deployments directly from Git. Here’s how:

  • Push your code → ArgoCD auto-syncs and deploys!
  • Rolling updates ensure no downtime – users always get a running instance
  • Health checks prevent broken deployments – if something fails, ArgoCD rolls back instantly
  • Version-controlled deployments – every change is trackable and reversible

Step 1: Start Minikube and Install ArgoCD

Ensure you have Minikube and kubectl installed.

# Start Minikube
minikube start

# Create the ArgoCD namespace
kubectl create namespace argocd

# Install ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Wait for the ArgoCD pods to be ready:

kubectl get pods -n argocd

Step 2: Expose and Access ArgoCD UI

Expose the ArgoCD API server:

kubectl port-forward svc/argocd-server -n argocd 8080:443

Retrieve the admin password:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 --decode; echo

Login to ArgoCD:

argocd login localhost:8080 --username admin --password <your-password>

Step 3: Connect ArgoCD to Your GitHub Repo

Use SSH authentication since GitHub removed password-based authentication.

argocd repo add git@github.com:ArvindRaja45/rep.git --ssh-private-key-path ~/.ssh/id_rsa

Step 4: Define Kubernetes Manifests

Deployment.yaml (Zero-Downtime Strategy)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: myrepo/my-app:latest
          ports:
            - containerPort: 80
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 10
Click Here to Copy YAML

Service.yaml (Expose the Application)

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP
Click Here to Copy YAML

Ingress.yaml (External Access)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
spec:
  rules:
    - host: my-app.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app-service
                port:
                  number: 80
Click Here to Copy YAML

Step 5: Deploy Application with ArgoCD

argocd app create my-app \
    --repo git@github.com:ArvindRaja45/rep.git \
    --path minikube \
    --dest-server https://kubernetes.default.svc \
    --dest-namespace default

Sync the application:

argocd app sync my-app

Monitor the deployment:

kubectl get pods -n default

Step 6: Enable Auto-Rollback on Failure

Edit Deployment.yaml to add readiness probe:

readinessProbe:
  httpGet:
    path: /
    port: 80
  initialDelaySeconds: 5
  periodSeconds: 10

Apply the changes:

kubectl apply -f deployment.yaml

If a deployment fails due to misconfiguration, ArgoCD will automatically rollback to the last successful version.

Why This is a Game-Changer

  • No more downtime – deployments are seamless and controlled
  • Fully automated – Git becomes your single source of truth
  • Faster rollbacks – mistakes are fixed in seconds, not hours
  • Scalable & production-ready – ArgoCD grows with your infrastructure

Conclusion

By integrating ArgoCD into your Kubernetes workflow, you can achieve zero-downtime deployments, automated rollbacks, and seamless application updates—all while ensuring stability and scalability. With Git as the single source of truth, your deployments become more reliable, repeatable, and transparent.

In today’s fast-paced DevOps world, automation is key to maintaining high availability and minimizing risk. Whether you’re running Minikube for development or scaling across multi-cluster production environments, ArgoCD is a game-changer for Kubernetes deployments.

How are you handling deployments in Kubernetes? Have you implemented ArgoCD yet? Share your thoughts!👇