Securing Registries and Pods in KinD
This guide focuses on security best practices for using KinD (Kubernetes in Docker) with a specific emphasis on securing container registries and pods.
Table of Contents
- Introduction
- Securing Container Registries
- Securing Pods in KinD
- Advanced Security Configurations
- Troubleshooting
- Additional Resources
Introduction
When using KinD for development, testing, or CI/CD pipelines, it's essential to follow security best practices even in these ephemeral environments. This guide will help you implement security measures for container registries and pods in your KinD clusters.
Securing Container Registries
Setting Up a Local Secure Registry
Setting up a local registry with TLS can improve security and allow you to test registry authentication configurations.
- Create a directory for your registry certificates:
mkdir -p ./certs- Generate self-signed certificates:
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ./certs/domain.key -x509 -days 365 -out ./certs/domain.crt -subj "/CN=registry.local" -addext "subjectAltName = DNS:registry.local"- Create a registry configuration file
registry-config.yaml:
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
tls:
certificate: /certs/domain.crt
key: /certs/domain.key- Start the registry container:
docker run -d \
--restart=always \
--name registry \
-v "$(pwd)"/certs:/certs \
-v "$(pwd)"/registry-config.yaml:/etc/docker/registry/config.yml \
-p 5000:5000 \
registry:2- Configure KinD to use this registry by creating a cluster config file
kind-with-registry.yaml:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
endpoint = ["https://registry.local:5000"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."registry.local:5000".tls]
ca_file = "/etc/ssl/certs/domain.crt"
nodes:
- role: control-plane
extraMounts:
- hostPath: ./certs/domain.crt
containerPath: /etc/ssl/certs/domain.crt- Create your KinD cluster with this configuration:
kind create cluster --config kind-with-registry.yamlUsing Private Registries with Authentication
To use private registries that require authentication:
- Create a Docker registry secret:
kubectl create secret docker-registry regcred \
--docker-server=<your-registry-server> \
--docker-username=<your-username> \
--docker-password=<your-password> \
--docker-email=<your-email>- Reference this secret in your pod specifications:
apiVersion: v1
kind: Pod
metadata:
name: private-image-pod
spec:
containers:
- name: private-image-container
image: private-registry.example.com/my-app:1.0
imagePullSecrets:
- name: regcred- For cluster-wide usage, add the secret to the default service account:
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}'Registry Mirroring
Registry mirroring can improve security by reducing dependencies on external registries and providing additional control over image sources.
- Create a containerd configuration file for registry mirroring:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://your-mirror-registry.example.com"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."your-mirror-registry.example.com".auth]
username = "username"
password = "password"
[plugins."io.containerd.grpc.v1.cri".registry.configs."your-mirror-registry.example.com".tls]
insecure_skip_verify = false
ca_file = "/path/to/ca.crt"- Create your cluster with this configuration.
Securing Pods in KinD
Pod Security Standards
Kubernetes Pod Security Standards (PSS) define different levels of security for pods:
- Create a namespace with security enforcement:
kubectl create namespace restricted-ns- Apply Pod Security Standards labels:
kubectl label --overwrite namespace restricted-ns \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted- Test deployment to the restricted namespace:
kubectl -n restricted-ns create deployment nginx --image=nginxThe deployment will fail unless the pod spec meets the restricted policy requirements.
Network Policies
Network Policies control pod-to-pod communication:
- Create a simple deny-all policy to start from a secure default:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: your-namespace
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress- Allow specific traffic with more targeted policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-specific-traffic
namespace: your-namespace
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 80Resource Limits
Setting resource limits prevents resource exhaustion attacks:
apiVersion: v1
kind: Pod
metadata:
name: secured-pod
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"You can enforce this with LimitRange objects:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: your-namespace
spec:
limits:
- default:
memory: 512Mi
cpu: 1
defaultRequest:
memory: 256Mi
cpu: 0.5
type: ContainersecurityContext Configuration
Configure pod and container security contexts:
apiVersion: v1
kind: Pod
metadata:
name: security-context-pod
spec:
securityContext:
runAsNonRoot: true
fsGroup: 2000
containers:
- name: secure-container
image: nginx
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsUser: 1000Advanced Security Configurations
OPA Gatekeeper Integration
OPA Gatekeeper can enforce custom security policies:
- Install Gatekeeper in your KinD cluster:
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.11/deploy/gatekeeper.yaml- Create a constraint template:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("Missing required labels: %v", [missing])
}- Apply a constraint:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
labels: ["team"]Image Vulnerability Scanning
Integrate Trivy for scanning images in your KinD cluster:
- Create a job to scan images:
apiVersion: batch/v1
kind: Job
metadata:
name: trivy-scanner
spec:
template:
spec:
containers:
- name: trivy
image: aquasec/trivy
args:
- image
- --severity
- HIGH,CRITICAL
- nginx:latest
restartPolicy: Never
backoffLimit: 1- For a more integrated approach, use admission controllers like Kyverno:
kubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.8.5/install.yaml- Create an image scanning policy:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: scan-image
spec:
validationFailureAction: Enforce
background: false
webhookTimeoutSeconds: 30
rules:
- name: verify-image
match:
resources:
kinds:
- Pod
validate:
message: "Image failed security scan"
image:
verifyImages:
- image: "*"
repositories:
- "myregistry.example.com/*"RBAC for KinD Clusters
Set up proper RBAC for your KinD cluster:
- Create a restricted role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]- Bind the role to a user or group:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioTroubleshooting
Private Registry Authentication Issues
If your pods can't pull from a private registry:
# Check if the secret exists
kubectl get secret regcred
# Check pod events
kubectl describe pod <pod-name>
# Verify the image pull secret is correctly specified
kubectl get pod <pod-name> -o yaml | grep imagePullSecrets -A 1Network Policy Troubleshooting
If network policies are blocking legitimate traffic:
# Deploy a debug pod to test connectivity
kubectl run tmp-shell --rm -i --tty --image nicolaka/netshoot -- /bin/bash
# Inside the pod, test connectivity
curl http://service-name
# Check network policies affecting a pod
kubectl get networkpolicy -ASecurity Context Issues
If a pod fails to start due to security context constraints:
# Check pod events
kubectl describe pod <pod-name>
# Test with a more permissive security context
kubectl run test-pod --image=nginx --overrides='{"spec":{"securityContext":{"runAsNonRoot":false}}}'Additional Resources
- KinD Security Documentation
- Kubernetes Security Best Practices
- OPA Gatekeeper
- Kubernetes Network Policies
- Container Security with Trivy
This guide provides an overview of securing registries and pods in KinD environments. As you build more complex systems, consider implementing additional security measures and conducting regular security audits.