AKS | Kyverno

Bonjour,

Dans cet article, je vais vous présenter un autre « policy engine » pour Kubernetes. Dans un précédent article, j’avais pu vous présenter la solution OPA Gatekeeper. Dans cet article, nous porterons une attention particulière au projet Kyverno. Ce projet est supporté par la CNCF Foundation dans la catégorie « Sandbox ».

Les principaux avantages d’utiliser la solution Kyverno versus OPA Gatekeeper sont:

  • Ne pas ré-apprendre un nouveau langage, les policies Kyverno sont des resources Kubernetes. Comme pour OPA Gatekeeper, ces policies peuvent être déployées en mode « audit » ou « enforce ».
  • En plus de la validation, Kyverno supporte également la mutation et la génération de resources.

Dans cet exemple, je vous présente comment déployer la solution Kyverno ainsi que comment créer et déployer une policy qui a comme objectif de forcer l’application d’un label lors de la création d’un resource group. J’avais pu vous présenter un exemple similaire au sein de l’article: AKS | OPA

Déployer Kyverno:

max@Azure:~$ kubectl create -f https://raw.githubusercontent.com/kyverno/kyverno/main/definitions/release/install.yaml
 namespace/kyverno created
 customresourcedefinition.apiextensions.k8s.io/clusterpolicies.kyverno.io created
 customresourcedefinition.apiextensions.k8s.io/clusterpolicyreports.wgpolicyk8s.io created
 customresourcedefinition.apiextensions.k8s.io/clusterreportchangerequests.kyverno.io created
 customresourcedefinition.apiextensions.k8s.io/generaterequests.kyverno.io created
 customresourcedefinition.apiextensions.k8s.io/policies.kyverno.io created
 customresourcedefinition.apiextensions.k8s.io/policyreports.wgpolicyk8s.io created
 customresourcedefinition.apiextensions.k8s.io/reportchangerequests.kyverno.io created
 serviceaccount/kyverno-service-account created
 clusterrole.rbac.authorization.k8s.io/kyverno:admin-policies created
 clusterrole.rbac.authorization.k8s.io/kyverno:admin-policyreport created
 clusterrole.rbac.authorization.k8s.io/kyverno:admin-reportchangerequest created
 clusterrole.rbac.authorization.k8s.io/kyverno:customresources created
 clusterrole.rbac.authorization.k8s.io/kyverno:generatecontroller created
 clusterrole.rbac.authorization.k8s.io/kyverno:policycontroller created
 clusterrole.rbac.authorization.k8s.io/kyverno:userinfo created
 clusterrole.rbac.authorization.k8s.io/kyverno:webhook created
 clusterrolebinding.rbac.authorization.k8s.io/kyverno:customresources created
 clusterrolebinding.rbac.authorization.k8s.io/kyverno:generatecontroller created
 clusterrolebinding.rbac.authorization.k8s.io/kyverno:policycontroller created
 clusterrolebinding.rbac.authorization.k8s.io/kyverno:userinfo created
 clusterrolebinding.rbac.authorization.k8s.io/kyverno:webhook created
 configmap/init-config created
 service/kyverno-svc created
 deployment.apps/kyverno created

Créer notre policy:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
   name: require-ns-labels
spec:
   validationFailureAction: enforce
   rules:
    - name: require-ns-labels
      match:
        resources:
          kinds:
            - Namespace
      validate:
        message: "The label my-app is required."
        pattern:
          metadata:
            labels:
              my-app: "?*"
max@Azure:~/clouddrive$ kubectl apply -f ns-label.yaml
clusterpolicy.kyverno.io/require-ns-labels created

Test:

max@Azure:~/clouddrive$ kubectl create namespace maxime
Error from server: admission webhook "validate.kyverno.svc" denied the request:

resource Namespace//maxime was blocked due to the following policies

require-ns-labels:
  require-ns-labels: 'validation error: The label my-app is required. Rule require-ns-labels failed at path /metadata/labels/'

max@Azure:~/clouddrive$ kubectl apply -f namespace.yaml
 namespace/maxime created

 max@Azure:~/clouddrive$ kubectl get ns --show-labels
 NAME              STATUS   AGE     LABELS
 default           Active   31m     
 kube-node-lease   Active   31m     
 kube-public       Active   31m     
 kube-system       Active   31m     addonmanager.kubernetes.io/mode=Reconcile,control-plane=true,kubernetes.io/cluster-service=true
 kyverno           Active   20m     
 maxime            Active   2m36s   my-app=maxapp

Lister les policies:

max@Azure:~/clouddrive$ kubectl get cpol
 NAME                BACKGROUND   ACTION
 require-ns-labels   true         enforce

max@Azure:~/clouddrive$ kubectl describe cpol require-ns-labels
 Name:         require-ns-labels
 Namespace:
 Labels:       
 Annotations:  pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,Job,StatefulSet,CronJob
 API Version:  kyverno.io/v1
 Kind:         ClusterPolicy
 Metadata:
   Creation Timestamp:  2020-12-31T20:39:24Z
   Generation:          1
   Managed Fields:
     API Version:  kyverno.io/v1
     Fields Type:  FieldsV1
     fieldsV1:
       f:metadata:
         f:annotations:
           .:
           f:kubectl.kubernetes.io/last-applied-configuration:
       f:spec:
         .:
         f:validationFailureAction:
     Manager:      kubectl-client-side-apply
     Operation:    Update
     Time:         2020-12-31T20:39:24Z
     API Version:  kyverno.io/v1
     Fields Type:  FieldsV1
     fieldsV1:
       f:spec:
         f:rules:
       f:status:
         .:
         f:averageExecutionTime:
         f:resourcesBlockedCount:
         f:ruleStatus:
         f:rulesAppliedCount:
         f:rulesFailedCount:
     Manager:         kyverno
     Operation:       Update
     Time:            2020-12-31T20:46:35Z
   Resource Version:  4981
   Self Link:         /apis/kyverno.io/v1/clusterpolicies/require-ns-labels
   UID:               0c6e3e76-307b-4f6e-884c-73708e740bde
 Spec:
   Background:  true
   Rules:
     Match:
       Resources:
         Kinds:
           Namespace
     Name:  require-ns-labels
     Validate:
       Message:  The label my-app is required.
       Pattern:
         Metadata:
           Labels:
             My - App:         ?*
   Validation Failure Action:  enforce
 Status:
   Average Execution Time:   165.212µs
   Resources Blocked Count:  2
   Rule Status:
     Applied Count:            2
     Average Execution Time:   165.212µs
     Failed Count:             2
     Resources Blocked Count:  2
     Rule Name:                require-ns-labels
   Rules Applied Count:        2
   Rules Failed Count:         2
 Events:                       

Supprimer une policy:

max@Azure:~/clouddrive$ kubectl delete cpol require-ns-labels
clusterpolicy.kyverno.io "require-ns-labels" deleted
maxl@Azure:~/clouddrive$ kubectl get cpol
No resources found

Créer une policy en audit mode:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
   name: audit-ns-labels
spec:
   validationFailureAction: audit
   rules:
    - name: audit-ns-labels
      match:
        resources:
          kinds:
            - Namespace
      validate:
        message: "The label my-app is required."
        pattern:
          metadata:
            labels:
              my-app: "?*"


max@Azure:~/clouddrive$ kubectl apply -f ns-label.yaml
clusterpolicy.kyverno.io/require-ns-labels created

max@Azure:~/clouddrive$ kubectl create namespace maxime
namespace/maxime created

max@Azure:~/clouddrive$ kubectl get cpol
NAME              BACKGROUND   ACTION
audit-ns-labels   true         audit

max@Azure:~/clouddrive$ kubectl describe cpol audit-ns-labels
 Name:         audit-ns-labels
 Namespace:
 Labels:       
 Annotations:  pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,Job,StatefulSet,CronJob
 API Version:  kyverno.io/v1
 Kind:         ClusterPolicy
 Metadata:
   Creation Timestamp:  2020-12-31T21:02:50Z
   Generation:          1
   Managed Fields:
     API Version:  kyverno.io/v1
     Fields Type:  FieldsV1
     fieldsV1:
       f:metadata:
         f:annotations:
           .:
           f:kubectl.kubernetes.io/last-applied-configuration:
       f:spec:
         .:
         f:validationFailureAction:
     Manager:      kubectl-client-side-apply
     Operation:    Update
     Time:         2020-12-31T21:02:50Z
     API Version:  kyverno.io/v1
     Fields Type:  FieldsV1
     fieldsV1:
       f:spec:
         f:rules:
       f:status:
         .:
         f:averageExecutionTime:
         f:ruleStatus:
         f:rulesFailedCount:
     Manager:         kyverno
     Operation:       Update
     Time:            2020-12-31T21:04:35Z
   Resource Version:  7592
   Self Link:         /apis/kyverno.io/v1/clusterpolicies/audit-ns-labels
   UID:               13bc5039-f6ac-4214-aa1a-40ddd932b39c
 Spec:
   Background:  true
   Rules:
     Match:
       Resources:
         Kinds:
           Namespace
     Name:  audit-ns-labels
     Validate:
       Message:  The label my-app is required.
       Pattern:
         Metadata:
           Labels:
             My - App:         ?*
   Validation Failure Action:  audit
 Status:
   Average Execution Time:  26.002µs
   Rule Status:
     Average Execution Time:  26.002µs
     Failed Count:            2
     Rule Name:               audit-ns-labels
   Rules Failed Count:        2
 Events:                      

Vous pouvez retrouver une suite d’exemples de policies à l’adresse ci-dessous: https://github.com/kyverno/kyverno/tree/main/samples

En conclusion, nous pouvons constater que Kyverno est une solution très intéressante et simple d’utilisation. A noter qu’une fonctionnalité de reporting est en cours de développement. Je reviendrai vous présenter cette fonctionnalité dans un prochain article.

Maxime.

AKS | OPA Gatekeeper

[English version below]

Bonjour,

Dans cet article, je vais vous présenter comment déployer la solution OPA Gatekeeper au sein d’un cluster AKS.

OPA Gatekeeper est un admission controller vous permettant d’auditer et d’appliquer des configurations de sécurité pour vos clusters AKS.

Déployer OPA Gatekeeper (Prebuilt image):

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.1/deploy/gatekeeper.yaml

Dans cet exemple, nous allons créer une policy qui va nécessiter d’avoir le label gatekeeper lors de la création d’un nouveau namespace. Pour cela nous allons créer un template puis une contrainte. Nous verrons dans un second temps comment créer une contrainte en « audit » mode.

Créer un template:

apiVersion: templates.gatekeeper.sh/v1beta1
  kind: ConstraintTemplate
  metadata:
    name: k8srequiredlabels
  spec:
    crd:
      spec:
        names:
          kind: K8sRequiredLabels
        validation:
          # Schema for the parameters field
          openAPIV3Schema:
            properties:
              labels:
                type: array
                items: string
    targets:
      - target: admission.k8s.gatekeeper.sh
        rego: |
          package k8srequiredlabels
      violation[{"msg": msg, "details": {"missing_labels": missing}}] {       provided := {label | input.review.object.metadata.labels[label]}       required := {label | label := input.parameters.labels[_]}       missing := required - provided       count(missing) > 0       msg := sprintf("you must provide labels: %v", [missing])     }

Créer une contrainte:

apiVersion: constraints.gatekeeper.sh/v1beta1
 kind: K8sRequiredLabels
 metadata:
   name: ns-must-have-gk
 spec:
   match:
     kinds:
       - apiGroups: [""]
         kinds: ["Namespace"]
   parameters:
     labels: ["gatekeeper"]

Test:

max@Azure:~/clouddrive$ kubectl create namespace maxime
 Error from server ([denied by ns-must-have-gk] you must provide labels: {"gatekeeper"}): admission webhook "validation.gatekeeper.sh" denied the request: [denied by ns-must-have-gk] you must provide labels: {"gatekeeper"}

Lister les contraintes:

max_coquerel@Azure:~/clouddrive$ kubectl get constraint
NAME AGE
ns-must-have-gk 80s

Créer une contrainte en mode audit:

apiVersion: constraints.gatekeeper.sh/v1beta1
 kind: K8sRequiredLabels
 metadata:
   name: ns-must-have-gk
 spec:
   enforcementAction: dryrun
   match:
     kinds:
       - apiGroups: [""]
         kinds: ["Namespace"]
   parameters:
     labels: ["gatekeeper"]


max@Azure:~/clouddrive$ kubectl describe constraint ns-must-have-gk
 Name:         ns-must-have-gk
 Namespace:
 Labels:       
 Annotations:  
 API Version:  constraints.gatekeeper.sh/v1beta1
 Kind:         K8sRequiredLabels

Status:
   Audit Timestamp:  2020-12-30T16:09:13Z
   By Pod:
     Constraint UID:       b245e684-174d-4b28-8be0-064722f2b4a3
     Enforced:             true
     Id:                   gatekeeper-audit-576f6d6f8d-kx8p6
     Observed Generation:  1
     Operations:
       audit
       status
     Constraint UID:       b245e684-174d-4b28-8be0-064722f2b4a3
     Enforced:             true
     Id:                   gatekeeper-controller-manager-85d8bf48c9-jqhq4
     Observed Generation:  1
     Operations:
       webhook
     Constraint UID:       b245e684-174d-4b28-8be0-064722f2b4a3
     Enforced:             true
     Id:                   gatekeeper-controller-manager-85d8bf48c9-mrj2w
     Observed Generation:  1
     Operations:
       webhook
     Constraint UID:       b245e684-174d-4b28-8be0-064722f2b4a3
     Enforced:             true
     Id:                   gatekeeper-controller-manager-85d8bf48c9-s2d86
     Observed Generation:  1
     Operations:
       webhook
   Total Violations:  6
   Violations:
     Enforcement Action:  dryrun
     Kind:                Namespace
     Message:             you must provide labels: {"gatekeeper"}
     Name:                default
     Enforcement Action:  dryrun
     Kind:                Namespace
     Message:             you must provide labels: {"gatekeeper"}
     Name:                gatekeeper-system
     Enforcement Action:  dryrun
     Kind:                Namespace
     Message:             you must provide labels: {"gatekeeper"}
     Name:                kube-node-lease
     Enforcement Action:  dryrun
     Kind:                Namespace
     Message:             you must provide labels: {"gatekeeper"}
     Name:                kube-public
     Enforcement Action:  dryrun
     Kind:                Namespace
     Message:             you must provide labels: {"gatekeeper"}
     Name:                kube-system
     Enforcement Action:  dryrun
     Kind:                Namespace
     Message:             you must provide labels: {"gatekeeper"}
     Name:                maxime
 Events:                  

Supprimer une contrainte:

max@Azure:~/clouddrive$ kubectl delete constraint ns-must-have-gk
 k8srequiredlabels.constraints.gatekeeper.sh "ns-must-have-gk" deleted

Maxime.


Hi,

In this article I will show you, how you can deploy OPA Gatekeeper in your AKS cluster.

OPA Gatekeeper is an admission which can be use to audit the security configuration or your AKS clusters.

L’attribut alt de cette image est vide, son nom de fichier est Screen-Shot-2020-12-30-at-12.02.46-PM.png.

Examples of security policies:

  • Do not allow privileged containers 
  • Ensure only allowed container image are allowed
  • Prevent host fine system mount 
  • Enforce labels
  • … and more … 

Deploy OPA Gatekeeper with the prebuilt image:

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.1/deploy/gatekeeper.yaml

In this article, we will create a new policy. The goal of this policy will to enforce a label at the namespace level. In the first we will create a template and a constraint. In the second part of this article we will see how we can create a constraint in audit mode.

Create a template:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
# Schema for the parameters field
openAPIV3Schema:
properties:
labels:
type: array
items: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg, "details": {"missing_labels": missing}}] { provided := {label | input.review.object.metadata.labels[label]} required := {label | label := input.parameters.labels[_]} missing := required - provided count(missing) > 0 msg := sprintf("you must provide labels: %v", [missing]) }

Créer une contrainte:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["gatekeeper"]

Test:

max@Azure:~/clouddrive$ kubectl create namespace maxime
Error from server ([denied by ns-must-have-gk] you must provide labels: {"gatekeeper"}): admission webhook "validation.gatekeeper.sh" denied the request: [denied by ns-must-have-gk] you must provide labels: {"gatekeeper"}

Constraints List:

max_coquerel@Azure:~/clouddrive$ kubectl get constraint
NAME AGE
ns-must-have-gk 80s

Create a constraint in audit mode:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
spec:
enforcementAction: dryrun
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["gatekeeper"]


max@Azure:~/clouddrive$ kubectl describe constraint ns-must-have-gk
Name: ns-must-have-gk
Namespace:
Labels:
Annotations:
API Version: constraints.gatekeeper.sh/v1beta1
Kind: K8sRequiredLabels

Status:
Audit Timestamp: 2020-12-30T16:09:13Z
By Pod:
Constraint UID: b245e684-174d-4b28-8be0-064722f2b4a3
Enforced: true
Id: gatekeeper-audit-576f6d6f8d-kx8p6
Observed Generation: 1
Operations:
audit
status
Constraint UID: b245e684-174d-4b28-8be0-064722f2b4a3
Enforced: true
Id: gatekeeper-controller-manager-85d8bf48c9-jqhq4
Observed Generation: 1
Operations:
webhook
Constraint UID: b245e684-174d-4b28-8be0-064722f2b4a3
Enforced: true
Id: gatekeeper-controller-manager-85d8bf48c9-mrj2w
Observed Generation: 1
Operations:
webhook
Constraint UID: b245e684-174d-4b28-8be0-064722f2b4a3
Enforced: true
Id: gatekeeper-controller-manager-85d8bf48c9-s2d86
Observed Generation: 1
Operations:
webhook
Total Violations: 6
Violations:
Enforcement Action: dryrun
Kind: Namespace
Message: you must provide labels: {"gatekeeper"}
Name: default
Enforcement Action: dryrun
Kind: Namespace
Message: you must provide labels: {"gatekeeper"}
Name: gatekeeper-system
Enforcement Action: dryrun
Kind: Namespace
Message: you must provide labels: {"gatekeeper"}
Name: kube-node-lease
Enforcement Action: dryrun
Kind: Namespace
Message: you must provide labels: {"gatekeeper"}
Name: kube-public
Enforcement Action: dryrun
Kind: Namespace
Message: you must provide labels: {"gatekeeper"}
Name: kube-system
Enforcement Action: dryrun
Kind: Namespace
Message: you must provide labels: {"gatekeeper"}
Name: maxime
Events:

Remove a constraint:

max@Azure:~/clouddrive$ kubectl delete constraint ns-must-have-gk
k8srequiredlabels.constraints.gatekeeper.sh "ns-must-have-gk" deleted

Maxime.

ACR | Importer des images

Bonjour,

Dans cet article, je vais vous présenter comment vous pouvez importer des images hébergées sur DockerHub directement avec l’aide Azure CLI. Avec cette méthode, vous n’avez pas besoin d’installer Docker sur votre poste de travail et faire un docker pull, re-taguer l’image puis réaliser un docker push vers votre registry.

Pour cela, je vous invite à utiliser la commande suivante:

az acr import \
--name myregistry \
--source docker.io/library/hello-world:latest \
--image hello-world:latest \
--username Docker_Hub_Username \
--password Docker_Hub_Token

Maxime.