Skip to content

Latest commit

 

History

History
310 lines (282 loc) · 10.7 KB

README_GETTING-STARTED-TUTORIAL.md

File metadata and controls

310 lines (282 loc) · 10.7 KB

Integrity Shield Getting Started Tutorial

This tutorial will guide you through:

  • Storing verification key as a Kubernetes Secret
  • Configuring ManifestIntegrityProfile to define which resource(s) should be protected
  • Creating a sample resource without signature
  • Generating the signature for the sample resource
  • Creating a sample resource with signature
  • [Detect mode] Checking the resource integrity status from the ManifestIntegrityState generated by observer
  • [Enforce mode] Checking the denied requests as Kubernetes Event

Integrity Shield provides a phased approach. It allows users to use signature-based protection first in inform mode and then switch to enforcement mode.

Store verification key as a Kubernetes Secret

Integrity Shield requires a secret that includes a pubkey for verifying signatures of resources that need to be protected. Integrity Shield supports X509, PGP or Sigstore key for signing resources. In this document, we use pgp signing.

Create a verification key as a Kubernetes Secret with the following command. Please check here to generate your own keypair.

gpg --export [email protected] > /tmp/pubring.gpg
kubectl create secret generic my-pubkey --from-file=key=/tmp/pubring.gpg -n integrity-shield-operator-system

If you do not have any PGP key or you want to use new key, generate new one and export it to a file. See this GitHub document.

Detect mode (Continuous Monitoring)

Create a sample ManifestIntegrityConstraint

A custom resource ManifestIntegrityConstraint (MIC) includes the definition of which resources should be protected with signature in a cluster by Integrity Shield.

This constraint enables us to monitor three resources ConfigMap, Deployment, and Service in a namespace secure-ns. Set the appropriate signer to "signers" field and create the following ManifestIntegrityConstraint resource.

See Define Protected Resources for detailed specs.

cat <<EOF | kubectl apply -f -
  apiVersion: constraints.gatekeeper.sh/v1beta1
  kind: ManifestIntegrityConstraint
  metadata:
    name: sample-constraint
  spec:
    match:
      kinds:
      - apiGroups:
        - ""
        kinds:
        - ConfigMap
        - Service
      - apiGroups:
        - "apps"
        kinds:
        - Deployment
      namespaces:
      - "secure-ns"
    parameters:
      action:
        mode: inform
      constraintName: sample-constraint
      signers:
      - [email protected]
      keyConfigs:
      - keySecretName: my-pubkey
        keySecretNamespace: integrity-shield-operator-system
EOF

manifestintegrityconstraint.constraints.gatekeeper.sh/sample-constraint created

Create a sample resource without signature

Run the following command to create a Yaml manifest for a sample configmap.

cat << EOF > /tmp/sample-cm.yaml
  apiVersion: v1
  kind: ConfigMap
  metadata:
    name: sample-cm
  data:
    key1: val1
    key2: val2
    comment: comment1
EOF

Create a sample configmap by the command below, and the configmap will be created because of inform mode.

$ kubectl apply -f /tmp/sample-cm.yaml -n secure-ns
configmap/sample-cm created

Check the resource integrity status from the ManifestIntegrityState generated by observer

Check the audit result for all constraints on the cluster with this command. you can see that some resources defined in sample-constraint are in invalid state because integrityshield.io/verifyResourceViolation label is true.

$ kubectl get mis --show-labels -n integrity-shield-operator-system                                                                                             
NAME                   AGE    LABELS
sample-constraint      2m1s   integrityshield.io/verifyResourceIgnored=false,integrityshield.io/verifyResourceViolation=true

By checking the verification result on per constraint, you can see which resource is violated from ManifestIntegrityState.

$ kubectl get mis sample-constraint -n integrity-shield-operator-system -o yaml                                                                               
apiVersion: apis.integrityshield.io/v1
kind: ManifestIntegrityState
metadata:
  labels:
    integrityshield.io/verifyResourceIgnored: "false"
    integrityshield.io/verifyResourceViolation: "true"
  name: sample-constraint
  namespace: integrity-shield-operator-system
spec:
  constraintName: sample-constraint
  nonViolations: null
  observationTime: "2021-10-14 13:04:55"
  totalViolations: 1
  violation: true
  violations:
  - apiGroup: ""
    apiVersion: v1
    kind: ConfigMap
    name: sample-cm
    namespace: secure-ns
    result: 'failed to verify signature: failed to get signature: `cosign.sigstore.dev/message`
      is not found in the annotations'
status: {}

Create a resource with signature

Generate siganture with the following command. Please see this document.

$ ./scripts/gpg-annotation-sign.sh [email protected] /tmp/sample-cm.yaml

Check the signature is attached to the sample resource.

$ less /tmp/sample-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-cm
  annotations:
    integrityshield.io/message: H4sIAMmiZmEAAzXLMQqAMAyF4T...
    integrityshield.io/signature: LS0tLS1CRUdJTiBQR1AgU...
data:
  key1: val1
  key2: val2
  comment: comment1

Apply a sample configmap by the command below.

$ kubectl apply -f /tmp/sample-cm.yaml -n secure-ns
configmap/sample-cm created

Check the resource integrity status again. You will see that the label of integrityshield.io/verifyResourceViolation has become false.

$ kubectl get mis --show-labels -n integrity-shield-operator-system
NAME                   AGE   LABELS
sample-constraint      22m   integrityshield.io/verifyResourceIgnored=false,integrityshield.io/verifyResourceViolation=false

Also, you can see sample-cm has no violation because it has a valid signature now.

$ kubectl get mis sample-constraint -n integrity-shield-operator-system -o yaml            
apiVersion: apis.integrityshield.io/v1
kind: ManifestIntegrityState
metadata:
  labels:
    integrityshield.io/verifyResourceIgnored: "false"
    integrityshield.io/verifyResourceViolation: "false"
  name: sample-constraint
  namespace: integrity-shield-operator-system
spec:
  constraintName: sample-constraint
  nonViolations:
  - apiGroup: ""
    apiVersion: ""
    kind: ConfigMap
    name: sample-cm
    namespace: secure-ns
    result: 'singed by a valid signer: [email protected]'
    sigRef: __embedded_in_annotation__
    signer: [email protected]
  observationTime: "2021-10-14 13:24:54"
  totalViolations: 0
  violation: false
  violations: null
status: {}

Enforce mode (Admission Control)

Reconfigure a sample ManifestIntegrityConstraint to turn on Enforce mode

Now, let's switch to Enforce mode. To enable enforce mode, change mode: inform to mode: enforce, then create the ManifestIntegrityConstraint.

cat <<EOF | kubectl apply -f -
  apiVersion: constraints.gatekeeper.sh/v1beta1
  kind: ManifestIntegrityConstraint
  metadata:
    name: sample-constraint
  spec:
    match:
      kinds:
      - apiGroups:
        - ""
        kinds:
        - ConfigMap
        - Service
      - apiGroups:
        - "apps"
        kinds:
        - Deployment
      namespaces:
      - "secure-ns"
    parameters:
      action:
        mode: enforce
      constraintName: sample-constraint
      signers:
      - [email protected]
      keyConfigs:
      - keySecretName: my-pubkey
        keySecretNamespace: integrity-shield-operator-system
EOF

Create a sample resource without signature

Run the following command to create a Yaml manifeset for a sample service.

cat << EOF > /tmp/sample-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: sample-service
spec:
  selector:
    app: SampleApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
EOF

Create a sample service by the command below, and the service will be blocked because the signature verification fails.

$ kubectl create -f /tmp/sample-svc.yaml -n secure-ns                                                                 
Error from server ([sample-constraint] denied; {"allow": false, "message": "failed to verify signature: failed to get signature: `cosign.sigstore.dev/message` is not found in the annotations"}): error when creating "/tmp/sample-svc.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [sample-constraint] denied; {"allow": false, "message": "failed to verify signature: failed to get signature: `cosign.sigstore.dev/message` is not found in the annotations"}

Check denied request

Integrity Shield generates an Event when it does not allow the admission request. You can see denied requests as Kubernetes Event like below.

$ kubectl get event -n secure-ns --field-selector type=IntegrityShield                                                     
LAST SEEN   TYPE              REASON   OBJECT                   MESSAGE
65s         IntegrityShield   Deny     service/sample-service   [sample-constraint]failed to verify signature: failed to get signature: `cosign.sigstore.dev/message` is not found in the annotations

Generating the signature for the sample resource

Generate a signature for a resource. Run the following script to generate a signature.

$ ./scripts/gpg-annotation-sign.sh [email protected] /tmp/sample-svc.yaml

Then, run the same command again to create Service. It should be successful this time because the resource has valid siganture.

$ kubectl create -f /tmp/sample-svc.yaml -n secure-ns                                                                
service/sample-service created

You can confirm that all protected resources are valid.

kind: ManifestIntegrityState
metadata:
  creationTimestamp: "2021-10-14T13:04:55Z"
  generation: 18
  labels:
    integrityshield.io/verifyResourceIgnored: "false"
    integrityshield.io/verifyResourceViolation: "false"
  name: sample-constraint
  namespace: integrity-shield-operator-system
spec:
  constraintName: sample-constraint
  nonViolations:
  - apiGroup: ""
    apiVersion: ""
    kind: Service
    name: sample-service
    namespace: secure-ns
    result: 'singed by a valid signer: [email protected]'
    sigRef: __embedded_in_annotation__
    signer: [email protected]
  - apiGroup: ""
    apiVersion: v1
    kind: ConfigMap
    name: sample-cm
    namespace: secure-ns
    result: 'singed by a valid signer: [email protected]'
    sigRef: __embedded_in_annotation__
    signer: [email protected]
  observationTime: "2021-10-14 14:29:49"
  totalViolations: 0
  violation: false
  violations: null
status: {}