Install and configure Helm 3 for Kubernetes package management with security and private repositories

Intermediate 45 min Apr 01, 2026 46 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Learn to install Helm 3 on Linux, configure private repositories with authentication, implement security best practices with RBAC, and integrate with CI/CD pipelines for automated Kubernetes deployments.

Prerequisites

  • Active Kubernetes cluster with kubectl configured
  • Administrative access to install packages
  • Basic understanding of Kubernetes concepts
  • GPG installed for chart signing (optional)

What this solves

Helm 3 is the de facto package manager for Kubernetes, allowing you to deploy, upgrade, and manage complex applications using pre-packaged charts. This tutorial covers installing Helm 3, configuring private repositories with authentication, implementing security best practices including RBAC, and integrating with CI/CD pipelines for production environments.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you have the latest package information and security updates.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install required dependencies

Install curl and other utilities needed for downloading and verifying Helm packages.

sudo apt install -y curl gnupg2 software-properties-common apt-transport-https
sudo dnf install -y curl gnupg2

Download and install Helm 3

Download the latest stable version of Helm 3 from the official repository and install it system-wide.

curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt update
sudo apt install -y helm
curl -L https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz -o helm-v3.13.2-linux-amd64.tar.gz
tar -zxvf helm-v3.13.2-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm
rm -rf linux-amd64 helm-v3.13.2-linux-amd64.tar.gz

Verify Helm installation

Confirm Helm is properly installed and check the version to ensure you have Helm 3.

helm version
helm help

Configure kubectl context

Ensure you have a working Kubernetes cluster connection before proceeding with Helm configuration. If you need to set up Kubernetes, refer to our Kubernetes cluster installation guide.

kubectl cluster-info
kubectl get nodes

Configure private Helm repositories

Add official Helm repositories

Add the official stable Helm chart repository and other commonly used repositories.

helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

Configure private repository with authentication

Add a private Helm repository with username and password authentication. Replace the URL and credentials with your actual private repository details.

helm repo add private-repo https://charts.example.com --username myuser --password mypassword
helm repo update

Configure repository with certificate authentication

For repositories using client certificates, configure authentication using certificate files.

mkdir -p ~/.helm/certs

Copy your certificate files to ~/.helm/certs/

helm repo add secure-repo https://secure-charts.example.com --cert-file ~/.helm/certs/client.crt --key-file ~/.helm/certs/client.key --ca-file ~/.helm/certs/ca.crt

List and verify repositories

Verify all repositories are properly configured and accessible.

helm repo list
helm search repo nginx

Create and deploy custom Helm charts

Create a new Helm chart

Generate a new Helm chart template with the standard directory structure and files.

helm create myapp
cd myapp
ls -la

Customize Chart.yaml

Edit the Chart.yaml file to define your application metadata and dependencies.

apiVersion: v2
name: myapp
description: A Helm chart for my application
type: application
version: 0.1.0
appVersion: "1.0.0"
maintainers:
  - name: Your Name
    email: your.email@example.com
keywords:
  - web
  - application
dependencies:
  - name: postgresql
    version: "12.1.2"
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled

Configure values.yaml

Define default configuration values that can be overridden during deployment.

replicaCount: 2

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "1.21.6"

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: myapp.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: myapp-tls
      hosts:
        - myapp.example.com

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: false
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

postgresql:
  enabled: true
  auth:
    postgresPassword: "secure-password-here"
    database: "myapp"

Deploy the chart

Install your custom chart with a specific release name and namespace.

helm dependency update
kubectl create namespace myapp
helm install myapp-release ./myapp --namespace myapp --create-namespace

Implement Helm security and RBAC

Create service account for Helm

Create a dedicated service account with minimal required permissions for Helm operations.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: helm-service-account
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: helm-cluster-role
rules:
  • apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  • apiGroups: ["apps"]
resources: ["deployments", "replicasets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  • apiGroups: ["networking.k8s.io"]
resources: ["ingresses"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: helm-cluster-role-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: helm-cluster-role subjects:
  • kind: ServiceAccount
name: helm-service-account namespace: kube-system
kubectl apply -f helm-rbac.yaml

Configure Helm security policies

Create a security policy to restrict Helm chart installations and enforce security standards.

apiVersion: v1
kind: ConfigMap
metadata:
  name: helm-security-policy
  namespace: kube-system
data:
  policy.yaml: |
    security:
      allowedRegistries:
        - "docker.io"
        - "quay.io"
        - "gcr.io"
        - "registry.example.com"
      forbiddenImages:
        - "*:latest"
        - "*:master"
      requiredLabels:
        - "app.kubernetes.io/name"
        - "app.kubernetes.io/version"
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        fsGroup: 2000
      resources:
        required: true
        limits:
          memory: "1Gi"
          cpu: "1000m"
kubectl apply -f helm-security-policy.yaml

Enable chart signing and verification

Generate GPG keys for signing charts and configure Helm to verify signatures before installation.

gpg --full-generate-key

Follow the prompts to create a key

gpg --list-secret-keys --keyid-format LONG

Note your key ID from the output

helm package --sign --key 'Your Name' --keyring ~/.gnupg/secring.gpg myapp helm verify myapp-0.1.0.tgz

Set up automated updates and rollbacks

Create upgrade script

Create an automated script for updating Helm releases with safety checks and rollback capabilities.

#!/bin/bash
set -e

RELEASE_NAME="$1"
CHART_PATH="$2"
NAMESPACE="$3"
VALUES_FILE="$4"

if [ $# -ne 4 ]; then
    echo "Usage: $0    "
    exit 1
fi

echo "Upgrading release: $RELEASE_NAME"
echo "Chart path: $CHART_PATH"
echo "Namespace: $NAMESPACE"
echo "Values file: $VALUES_FILE"

Backup current release

echo "Creating backup..." helm get all $RELEASE_NAME --namespace $NAMESPACE > "backup-$RELEASE_NAME-$(date +%Y%m%d-%H%M%S).yaml"

Update dependencies

echo "Updating dependencies..." helm dependency update $CHART_PATH

Dry run first

echo "Performing dry run..." helm upgrade $RELEASE_NAME $CHART_PATH --namespace $NAMESPACE --values $VALUES_FILE --dry-run

Actual upgrade

echo "Performing upgrade..." helm upgrade $RELEASE_NAME $CHART_PATH --namespace $NAMESPACE --values $VALUES_FILE --wait --timeout 10m

Verify deployment

echo "Verifying deployment..." kubectl get pods --namespace $NAMESPACE helm test $RELEASE_NAME --namespace $NAMESPACE echo "Upgrade completed successfully!"
chmod +x helm-upgrade.sh

Configure automatic rollback

Create a monitoring script that automatically rolls back deployments if health checks fail.

#!/bin/bash
set -e

RELEASE_NAME="$1"
NAMESPACE="$2"
HEALTH_CHECK_URL="$3"
MAX_RETRIES=5
RETRY_INTERVAL=30

echo "Monitoring release: $RELEASE_NAME in namespace: $NAMESPACE"

for i in $(seq 1 $MAX_RETRIES); do
    echo "Health check attempt $i/$MAX_RETRIES"
    
    if curl -f -s "$HEALTH_CHECK_URL" > /dev/null; then
        echo "Health check passed"
        exit 0
    else
        echo "Health check failed, attempt $i/$MAX_RETRIES"
        
        if [ $i -eq $MAX_RETRIES ]; then
            echo "All health checks failed, initiating rollback..."
            helm rollback $RELEASE_NAME --namespace $NAMESPACE
            echo "Rollback completed"
            exit 1
        else
            echo "Waiting $RETRY_INTERVAL seconds before next attempt..."
            sleep $RETRY_INTERVAL
        fi
    fi
done
chmod +x helm-monitor.sh

Integrate with CI/CD pipelines

Create GitLab CI pipeline configuration

Configure a GitLab CI pipeline for automated Helm deployments. This integrates well with GitLab CE installations.

stages:
  - lint
  - build
  - test
  - deploy-staging
  - deploy-production

variables:
  HELM_VERSION: "3.13.2"
  KUBECTL_VERSION: "1.28.4"
  CHART_PATH: "./charts/myapp"

before_script:
  - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
  - chmod 700 get_helm.sh
  - ./get_helm.sh --version v$HELM_VERSION
  - curl -LO "https://dl.k8s.io/release/v$KUBECTL_VERSION/bin/linux/amd64/kubectl"
  - chmod +x kubectl && sudo mv kubectl /usr/local/bin/

helm-lint:
  stage: lint
  script:
    - helm lint $CHART_PATH
    - helm template myapp $CHART_PATH --values $CHART_PATH/values-staging.yaml > /dev/null
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

helm-package:
  stage: build
  script:
    - helm dependency update $CHART_PATH
    - helm package $CHART_PATH --version $CI_COMMIT_SHA
  artifacts:
    paths:
      - "*.tgz"
    expire_in: 1 week
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

deploy-staging:
  stage: deploy-staging
  environment:
    name: staging
    url: https://staging.example.com
  script:
    - kubectl config use-context staging-cluster
    - helm upgrade --install myapp-staging $CHART_PATH 
        --namespace staging 
        --values $CHART_PATH/values-staging.yaml 
        --set image.tag=$CI_COMMIT_SHA 
        --wait --timeout 10m
    - helm test myapp-staging --namespace staging
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

deploy-production:
  stage: deploy-production
  environment:
    name: production
    url: https://app.example.com
  script:
    - kubectl config use-context production-cluster
    - helm upgrade --install myapp-prod $CHART_PATH 
        --namespace production 
        --values $CHART_PATH/values-production.yaml 
        --set image.tag=$CI_COMMIT_SHA 
        --wait --timeout 15m
    - helm test myapp-prod --namespace production
  when: manual
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

Create environment-specific values files

Create separate values files for different environments to manage configuration differences.

replicaCount: 1

image:
  repository: registry.example.com/myapp
  tag: latest

service:
  type: NodePort
  port: 80

ingress:
  enabled: true
  hosts:
    - host: staging.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: staging-tls
      hosts:
        - staging.example.com

resources:
  limits:
    cpu: 200m
    memory: 256Mi
  requests:
    cpu: 100m
    memory: 128Mi

postgresql:
  enabled: true
  auth:
    database: "myapp_staging"
replicaCount: 3

image:
  repository: registry.example.com/myapp
  tag: stable

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  hosts:
    - host: app.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: production-tls
      hosts:
        - app.example.com

resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

postgresql:
  enabled: false  # Use external database in production

Verify your setup

Test your Helm installation and configurations with these verification commands:

# Verify Helm version and functionality
helm version
helm list --all-namespaces

Test repository access

helm repo list helm search repo nginx

Verify RBAC configuration

kubectl auth can-i create deployments --as=system:serviceaccount:kube-system:helm-service-account kubectl get clusterrolebindings | grep helm

Check deployed releases

helm list --namespace myapp helm status myapp-release --namespace myapp

Verify chart signing

helm verify myapp-0.1.0.tgz

Test rollback functionality

helm history myapp-release --namespace myapp helm rollback myapp-release 1 --namespace myapp --dry-run
Note: If you're using ArgoCD for GitOps, you can integrate it with Helm for declarative deployments. Check our ArgoCD installation guide for details.

Common issues

Symptom Cause Fix
"release not found" error Release installed in different namespace helm list --all-namespaces to find release
Repository authentication fails Incorrect credentials or expired tokens helm repo remove repo-name && helm repo add repo-name URL --username user --password pass
Chart dependencies not found Dependencies not updated helm dependency update before installation
Permission denied errors Insufficient RBAC permissions Review and update ClusterRole permissions in helm-rbac.yaml
Upgrade hangs or times out Resource constraints or failed readiness probes helm upgrade --timeout 15m and check pod logs
Chart verification fails Missing or incorrect GPG keys gpg --import public-key.asc and verify key trust
Values not applied correctly YAML syntax errors or wrong file path helm template to debug value interpolation
Rollback fails Previous revision corrupted or missing helm history release-name and rollback to known good revision
Warning: Never store sensitive credentials in plain text values files. Use Kubernetes secrets, external secret management systems, or encrypted values with tools like helm-secrets plugin.

Next steps

Automated install script

Run this to automate the entire setup

#helm #kubernetes #package-management #helm-charts #k8s-deployment

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer