티스토리 뷰

Cloud/Kubernetes

trivy-operator

Jacob_baek 2023. 4. 1. 22:10

trivy는 security scanner로 다양한 방식의 스캔을 제공하고 명령 기반의 실행방식과 결과를 제공한다.
명령 기반이기에 harbor와 같은 registry나 gitlab, circleCI와 같은 CI/CD 도구들과 통합되지 않는 경우 코드기반의 수작업이 사전에 필요하다는 의미이다. 즉, 다양한 방식의 스캔과 이에 따른 결과를 제공하기에 이를 활용하기 위해서는 추가적인 사용법 및 기타 도구들과의 통합 작업이 필요하다. 이를 한번에 제공하는 도구가 있다면 좋을듯 한데 이런 기능을 제공해주는 trivy-operator가 존재하여 이에 대하여 알아보기로 하자.

Trivy-operator

Trivy-operator는 kubernetes cluster를 보안 이슈에 대해 지속적으로 scan 하고 CRD로 보안 리포트를 생성하는 native operator이다. operator가 배포된 cluster에서 지정된 scan(ex. 취약점/노출된secret/RBAC scan 등)을 job형태로 생성 및 수행하고 이에 대한 report를 생성한다. (혹여나 오해가 있을수 있는데 report는 문서로 export 하는 report가 아닌 report를 생성할 기반 data라 볼수 있다.)

아래 aquasecurity blog에 trivy와의 차이점(실제 operator의 발현배경을 이해해볼수 있는)을 설명해주고 있으니 이를 참고하면 좀더 이해가 쉬울것이다.

다음과 같은 주요 report를 생성한다.

  • 취약점 스캔
  • 설정감사 스캔
  • 노출된 Secret 스캔
  • RBAC 스캔
  • K8s 주요 구성요소(etcd, apiserver, scheduler, controller-manager, 등)에 대한 평가 스캔
  • 컴플라이언스(NSA, CISA K8s hardening guidance, CIS k8s benchmark 등) 스캔
  • 출처 : https://github.com/aquasecurity/trivy-operator#introduction

Installation

설치는 간단하게 helm chart로 배포가 가능하다.

jacob@laptop:~ $ helm repo add aquasecurity https://aquasecurity.github.io/helm-charts/
jacob@laptop:~ $ helm install trivy-operator aquasecurity/trivy-operator   --namespace trivy-system   --create-namespace   --set="trivy.ignoreUnfixed=true"   --version 0.11.1
NAME: trivy-operator
LAST DEPLOYED: Sun Feb 19 18:11:23 2023
NAMESPACE: trivy-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
You have installed Trivy Operator in the trivy-system namespace.
It is configured to discover Kubernetes workloads and resources in
all namespace(s).

Inspect created VulnerabilityReports by:

    kubectl get vulnerabilityreports --all-namespaces -o wide

Inspect created ConfigAuditReports by:

    kubectl get configauditreports --all-namespaces -o wide

Inspect the work log of trivy-operator by:

    kubectl logs -n trivy-system deployment/trivy-operator

배포가 되면 trivy-operator가 deployment 형태로 배포되어진다.

아래 yaml 로 배포하는 방식도 존재하니 편한 방식으로 선택하여 배포를 진행한다.

배포가 완료되면 다음과 같은 CRD와 각 object 들이 생성되어진다.

jacob@laptop:~ $ kubectl get crds | grep aquasecurity
clustercompliancereports.aquasecurity.github.io                  2023-02-19T09:11:23Z
clusterconfigauditreports.aquasecurity.github.io                 2023-02-19T09:11:23Z
clusterinfraassessmentreports.aquasecurity.github.io             2023-02-19T09:11:23Z
clusterrbacassessmentreports.aquasecurity.github.io              2023-02-19T09:11:23Z
configauditreports.aquasecurity.github.io                        2023-02-19T09:11:23Z
exposedsecretreports.aquasecurity.github.io                      2023-02-19T09:11:23Z
infraassessmentreports.aquasecurity.github.io                    2023-02-19T09:11:23Z
rbacassessmentreports.aquasecurity.github.io                     2023-02-19T09:11:23Z
vulnerabilityreports.aquasecurity.github.io                      2023-02-19T09:11:23Z

jacob@laptop:~ $ kubectl get all -n trivy-system
NAME                                  READY   STATUS    RESTARTS   AGE
pod/trivy-operator-744896d6cc-mz7nc   1/1     Running   0          107m

NAME                     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/trivy-operator   ClusterIP   None         <none>        80/TCP    41d

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/trivy-operator   1/1     1            1           41d

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/trivy-operator-744896d6cc   1         1         1       15d

jacob@laptop:~ $ kubectl get cm -n trivy-system | grep trivy
trivy-operator                   6      41d
trivy-operator-aqua-config       13     40d
trivy-operator-policies-config   0      41d
trivy-operator-trivy-config      17     41d

jacob@laptop:~ $ kubectl get secret -n trivy-system
NAME                                   TYPE                 DATA   AGE
sh.helm.release.v1.trivy-operator.v1   helm.sh/release.v1   1      41d
trivy-operator                         Opaque               0      41d
trivy-operator-trivy-config            Opaque               0      41d

configuration

trivy-operator는 다양한 보안 리포트를 만들어내는 도구이기에 어떻게 만들지 언제 만들지 등등
사전 설정이 필요하다. 아래는 기본적으로 제공하고 있는 설정 정보이다.

  • trivy-operator-policies-config : built-in 구성 감사 정책 리스트라 되어있으나 실제 data로 저장된것은 없다. 예상하기론 custom configuration audit 와 같은 custom audit policy를 사용하고자 할때 사용될 것으로 예상되나 관련된 문서가 없어 코드 기반으로 분석한후 추가해볼 예정이다.
  • trivy-operator-trivy-config : trivy scan 시 사용되는 기본 config로 resource 제한 및 취약점 db 저장소 등을 설정할 수 있다.
  • trivy-operator-aqua-config : trivy-operator-trivy-config와 거의 유사한 설정이 존재한다.(정확한 활용처는 확인이 필요하지만 aquasecurity 제품 구매후 사용시 활용되는 설정으로 유추된다.)
  • operator deployment내 environment : operator에 의해 생성되는 report와 관련된 설정

위와 같은 설정중 trivy-operator의 주요기능인 스캔에 따른 report 생성과 관련된 설정에 대하여 좀더 알아보도록 하자.
아래는 기본(일부 설정이 변경되어 있다)적으로 제공되는 environment value이다.

jacob@laptop:~ $ kubectl get deploy trivy-operator -n trivy-system -o jsonpath='{.spec.template.spec.containers[0].env}' | jq
[
  {
    "name": "OPERATOR_NAMESPACE",
    "value": "trivy-system"
  },
  {
    "name": "OPERATOR_TARGET_NAMESPACES"
  },
  {
    "name": "OPERATOR_EXCLUDE_NAMESPACES"
  },
  {
    "name": "OPERATOR_TARGET_WORKLOADS",
    "value": "pod,replicaset,replicationcontroller,statefulset,daemonset,cronjob,job"
  },
  {
    "name": "OPERATOR_SERVICE_ACCOUNT",
    "value": "trivy-operator"
  },
  {
    "name": "OPERATOR_LOG_DEV_MODE",
    "value": "false"
  },
  {
    "name": "OPERATOR_SCAN_JOB_TIMEOUT",
    "value": "5m"
  },
  {
    "name": "OPERATOR_CONCURRENT_SCAN_JOBS_LIMIT",
    "value": "10"
  },
  {
    "name": "OPERATOR_SCAN_JOB_RETRY_AFTER",
    "value": "30s"
  },
  {
    "name": "OPERATOR_BATCH_DELETE_LIMIT",
    "value": "10"
  },
  {
    "name": "OPERATOR_BATCH_DELETE_DELAY",
    "value": "10s"
  },
  {
    "name": "OPERATOR_METRICS_BIND_ADDRESS",
    "value": ":8080"
  },
  {
    "name": "OPERATOR_METRICS_FINDINGS_ENABLED",
    "value": "true"
  },
  {
    "name": "OPERATOR_METRICS_VULN_ID_ENABLED",
    "value": "false"
  },
  {
    "name": "OPERATOR_HEALTH_PROBE_BIND_ADDRESS",
    "value": ":9090"
  },
  {
    "name": "OPERATOR_VULNERABILITY_SCANNER_ENABLED",
    "value": "true"
  },
  {
    "name": "OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS",
    "value": "true"
  },
  {
    "name": "OPERATOR_SCANNER_REPORT_TTL",
    "value": "120m"
  },
  {
    "name": "OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED",
    "value": "true"
  },
  {
    "name": "OPERATOR_RBAC_ASSESSMENT_SCANNER_ENABLED",
    "value": "true"
  },
  {
    "name": "OPERATOR_INFRA_ASSESSMENT_SCANNER_ENABLED",
    "value": "true"
  },
  {
    "name": "OPERATOR_CONFIG_AUDIT_SCANNER_SCAN_ONLY_CURRENT_REVISIONS",
    "value": "true"
  },
  {
    "name": "OPERATOR_EXPOSED_SECRET_SCANNER_ENABLED",
    "value": "true"
  },
  {
    "name": "OPERATOR_WEBHOOK_BROADCAST_URL",
    "value": "postee-svc.default.svc.cluster.local:8082"
  },
  {
    "name": "OPERATOR_WEBHOOK_BROADCAST_TIMEOUT",
    "value": "20s"
  },
  {
    "name": "OPERATOR_PRIVATE_REGISTRY_SCAN_SECRETS_NAMES",
    "value": "{}"
  },
  {
    "name": "OPERATOR_ACCESS_GLOBAL_SECRETS_SERVICE_ACCOUNTS",
    "value": "true"
  },
  {
    "name": "OPERATOR_BUILT_IN_TRIVY_SERVER",
    "value": "false"
  },
  {
    "name": "TRIVY_SERVER_HEALTH_CHECK_CACHE_EXPIRATION",
    "value": "10h"
  },
  {
    "name": "OPERATOR_MERGE_RBAC_FINDING_WITH_CONFIG_AUDIT",
    "value": "false"
  }
]

몇가지 환경변수들을 알아보자면 다음과 같다.

  • OPERATOR_EXCLUDE_NAMESPACES : (,)로 구분된 제외될 namespace를 지정할 수 있다.
  • OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED : 설정 검사를 수행할지 설정 (def: false)
  • OPERATOR_VULNERABILITY_SCANNER_ENABLED : 취약점 스캔을 수행할지 설정 (def: true)
  • OPERATOR_RBAC_ASSESSMENT_SCANNER_ENABLED : rbac 평가 스캔을 수행할지 설정 (def: true)
  • OPERATOR_CONCURRENT_SCAN_JOBS_LIMIT : operator에 의해 몇개의 동시작업을 수행할지 결정 (def: 10)
  • OPERATOR_EXPOSED_SECRET_SCANNER_ENABLED : 노출된 secre에 대한 스캔을 수행할지 결정 (def: true)
  • OPERATOR_SCANNER_REPORT_TTL : report의 저장기간을 지정한다. (def: 24h 이며 ""은 제한없이 저장) 실제 report 의 생성주기로 활용할 수 있다.
  • OPERATOR_BUILT_IN_TRIVY_SERVER : 실질적인 scan을 수행할 trivy를 cluster 내에서 동작시킬지 아니면 remote 서버를 사용할지 결정할수 있다. 원격의 경우 trivy.mode = ClientServer and serverURL = http://[server Service Name].[trivy Operator Namespace]:4975 와 같은 설정이 필요하다.
    ghcr.io/aquasecurity/trivy-db
    https://github.com/aquasecurity/trivy-db/pkgs/container/trivy-db

아래에 주요한 operator 설정에 대한 설명이 있으니 이를 참고하여 설정을 진행한다.

참고로 실제 동작되는 job 형태의 pod는 다음과 같이 구성 및 동작된다.

jacob@laptop:~ $ kubectl get pod scan-vulnerabilityreport-59854c765-kcw8k -n trivy-system -o jsonpath='{.spec.containers}' | jq
[
  {
    "args": [
      "-c",
      "trivy image --slow 'mcr.microsoft.com/azuremonitor/containerinsights/ciprod:ciprod01182023-095c864a' --scanners vuln,secret --cache-dir /tmp/trivy/.cache --quiet --skip-db-update --format json > /tmp/scan/result_ama-logs.json &&  bzip2 -c /tmp/scan/result_ama-logs.json | base64"
    ],
    "command": [
      "/bin/sh"
    ],
    "env": [
      {
        "name": "TRIVY_SEVERITY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.severity",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_IGNORE_UNFIXED",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.ignoreUnfixed",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_OFFLINE_SCAN",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.offlineScan",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_TIMEOUT",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.timeout",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_FILES",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipFiles",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_DIRS",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipDirs",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTP_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTPS_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpsProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "NO_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.noProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      }
    ],
    "image": "ghcr.io/aquasecurity/trivy:0.37.2",
    "imagePullPolicy": "IfNotPresent",
    "name": "ama-logs",
    "resources": {
      "limits": {
        "cpu": "500m",
        "memory": "500M"
      },
      "requests": {
        "cpu": "100m",
        "memory": "100M"
      }
    },
    "securityContext": {
      "allowPrivilegeEscalation": false,
      "capabilities": {
        "drop": [
          "ALL"
        ]
      },
      "privileged": false,
      "readOnlyRootFilesystem": true
    },
    "terminationMessagePath": "/dev/termination-log",
    "terminationMessagePolicy": "FallbackToLogsOnError",
    "volumeMounts": [
      {
        "mountPath": "/tmp",
        "name": "tmp"
      },
      {
        "mountPath": "/tmp/scan",
        "name": "scanresult"
      }
    ]
  }
]

동작되는 job에서 볼수 있듯이 trivy-operator-trivy-config의 설정을 기반으로 trivy가 동작된다.

궁금증 #1 : 원격의 trivy server를 이용할 수 있는지

trivy 실행을 standalone 형태로 할지 clientServer 형태로 할지 정할 수 있다.

궁금증 #2 : scan 수행 및 report 생성 주기를 지정할수 있는지

앞선 trivy-operator의 설정중 OPERATOR_SCANNER_REPORT_TTL를 변경하여 report 생성주기를 변경해볼수 있었다.
OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL 기본 24h이며 해당 시간이 지나면 기존 report는 삭제되고 새로운 report가 생성된다.
다만 해당 env는 vulnenrability에 한정되어 다른 report(ex. clusterinfraassessmentreport 에는 반영되지 않는다.

How to use

trivy-operator를 설치하게 되면 앞서 언급했던 CRD들이 생성되어진다.
그리고 그에 맞는 report 들이 생성되어진다.

report는 다음 CRD 항목을 기반으로 생성되어진다.

jacob@laptop:~ $ kubectl get crd --show-labels | grep aquasecurity
clustercompliancereports.aquasecurity.github.io        2023-02-19T09:11:23Z   <none>
clusterconfigauditreports.aquasecurity.github.io       2023-02-19T09:11:23Z   <none>
clusterinfraassessmentreports.aquasecurity.github.io   2023-02-19T09:11:23Z   <none>
clusterrbacassessmentreports.aquasecurity.github.io    2023-02-19T09:11:23Z   <none>
configauditreports.aquasecurity.github.io              2023-02-19T09:11:23Z   <none>
exposedsecretreports.aquasecurity.github.io            2023-02-19T09:11:23Z   <none>
infraassessmentreports.aquasecurity.github.io          2023-02-19T09:11:23Z   <none>
rbacassessmentreports.aquasecurity.github.io           2023-02-19T09:11:23Z   <none>
vulnerabilityreports.aquasecurity.github.io            2023-02-19T09:11:23Z   <none>

각 report는 다음과 같은 구조의 결과를 보여준다.(일부 다르긴하지만 구조는 비슷하다.)

report:
  updateTimestamp: '2023-03-31T17:11:15Z'
  scanner:
    name: Trivy 
    vendor: Aqua Security
    version: '0.12.1'
  summary:
    criticalCount: 1
    highCount: 0
    lowCount: 3
    mediumCount: 0
  checks:
    - category: Security
      checkID: hostPIDSet
      messages:
        - Host PID is not configured
      severity: CRITICAL
      success: true

1. clustercompliancereports

cluster 전반의 자원에 대한 scan을 진행한 report이다.
NSA, CISA Kubernetes Hardening Guidance v1.2 / CIS Benchmark for Kubernetes v1.23 기반에 사전에 정의된 spec으로 report를 생성한다.

아래와 같이 clustercompliancereports crd로 관리되어지며 각 항목은 CIS에서 발행한 pdf 문서내에 존재하는 id 별로 항목들이 존재하며

jacob@laptop:~ $ kubectl get clustercompliancereports
NAME   AGE
cis    41d
nsa    41d
jacob@laptop:~ $ kubectl get clustercompliancereports/cis -o jsonpath='{.status.summaryReport.controlCheck[0]}' | jq
{
  "id": "1.1.1",
  "name": "Ensure that the API server pod specification file permissions are set to 600 or more restrictive",
  "severity": "HIGH",
  "totalFail": 0
}

이에 대한 pass 여부를 아래와 같이 알수 있다.

jacob@laptop:~ $ kubectl get clustercompliancereports/cis -o jsonpath='{.status.summary}' | jq
{
  "failCount": 20,
  "passCount": 96
}

참고로 실제 생성된 report를 보면 cron 주기가 설정되어 있다.

jacob@laptop:~ $ kubectl get clustercompliancereports cis -o jsonpath='{.spec}' | jq -r '.cron, .reportType'
0 */6 * * *
summary

2. clusterconfigauditreports

아래5번항목을 cluster 기준으로 스캔한 report이다.
(해당 값은 테스트시 확인되지 않아 이에 대해서는 차후 테스트 하면서 업데이트 해볼 예정입니다.)

jacob@laptop:~ $ kubectl get clusterconfigauditreports
No resources found

3. clusterinfraassessmentreports

kubernetes 노드에 대한 report로 아래와 같은 node 이름별로 report를 생성한다.

jacob@laptop:~ $ kubectl get clusterinfraassessmentreports
NAME         SCANNER   AGE
agentpool1   Trivy     16m
agentpool2   Trivy     17m

확인된 항목은 .report.checks 에서 확인이 가능하다.

jacob@laptop:~  $ kubectl get clusterinfraassessmentreports agentpool1 -o jsonpath='{.report.checks[]}' | jq
{
  "category": "Kubernetes Security Check",
  "checkID": "KCV0082",
  "description": "Disable the read-only port.",
  "messages": [
    "Verify that the --read-only-port argument is set to 0"
  ],
  "severity": "HIGH",
  "success": false,
  "title": "Verify that the --read-only-port argument is set to 0"
}

사용된 scanner와 summary 항목으로 결과를 제공한다.

jacob@laptop:~  $ kubectl  get clusterinfraassessmentreports agentpool1 -o jsonpath='{.report}' | jq -r '.scanner, .summary'
{
  "name": "Trivy",
  "vendor": "Aqua Security",
  "version": "0.11.1"
}
{
  "criticalCount": 5,
  "highCount": 5,
  "lowCount": 0,
  "mediumCount": 0
}

4. clusterrbacassessmentreports

clusterrole에 대해 스캔을 진행하고

k get clusterrbacassessmentreports
NAME                                                      SCANNER   AGE
clusterrole-54ccb57cc4                                    Trivy     41d
clusterrole-54cdc9b678                                    Trivy     41d
clusterrole-5585c7b9ff                                    Trivy     41d
clusterrole-5586cb67bd                                    Trivy     22d
clusterrole-55bf6f9598                                    Trivy     41d
clusterrole-565cd5fdf                                     Trivy     41d
clusterrole-56749cc55b                                    Trivy     12d

아래와 같은 항목들에 대한 검사 결과를 확인할 수 있다.

jacob@laptop:~ $ kubectl get clusterrbacassessmentreports clusterrole-7b884bc5d8 -o jsonpath='{.report}' | jq
{
  "checks": [
    {
      "category": "Kubernetes Security Check",
      "checkID": "KSV049",
      "description": "Some workloads leverage configmaps to store sensitive data or configuration parameters that affect runtime behavior that can be modified by an attacker or combined with another issue to potentially lead to compromise.",
      "messages": [
        "ClusterRole 'system:aggregate-to-edit' should not have access to resource 'configmaps' for verbs [\"create\", \"update\", \"patch\", \"delete\", \"deletecollection\", \"impersonate\", \"*\"]"
      ],
      "severity": "MEDIUM",
      "success": false,
      "title": "Do not allow management of configmaps"
    },
    {
      "category": "Kubernetes Security Check",
      "checkID": "KSV056",
      "description": "The ability to control which pods get service traffic directed to them allows for interception attacks. Controlling network policy allows for bypassing lateral movement restrictions.",
      "messages": [
        "ClusterRole 'system:aggregate-to-edit' should not have access to resources [\"services\", \"endpoints\", \"endpointslices\", \"networkpolicies\", \"ingresses\"] for verbs [\"create\", \"update\", \"patch\", \"delete\", \"deletecollection\", \"impersonate\", \"*\"]"
      ],
      "severity": "HIGH",
      "success": false,
      "title": "Do not allow management of networking resources"
    },
    {
      "category": "Kubernetes Security Check",
      "checkID": "KSV041",
      "description": "Check whether role permits managing secrets",
      "messages": [
        "Role permits management of secret(s)"
      ],
      "severity": "CRITICAL",
      "success": false,
      "title": "Do not allow management of secrets"
    },
    {
      "category": "Kubernetes Security Check",
      "checkID": "KSV048",
      "description": "Check whether role permits update/create of a malicious pod",
      "messages": [
        "Role permits create/update of a malicious pod"
      ],
      "severity": "HIGH",
      "success": false,
      "title": "Do not allow update/create of a malicious pod"
    }
  ],
  "scanner": {
    "name": "Trivy",
    "vendor": "Aqua Security",
    "version": "0.11.1"
  },
  "summary": {
    "criticalCount": 1,
    "highCount": 2,
    "lowCount": 0,
    "mediumCount": 1
  }
}

5. configauditreports

kubernetes 의 workload에 대한 스캔 결과이다.
이름 구성은 [workload-kind]-[workload-name]으로 이루어진다.
실제 결과를 보면 statefulset, daemonset, service, replicaset, networkpolicy 등 다양하게 존재한다.

jacob@laptop:~ $ kubectl get configauditreports -n default
NAME                                              SCANNER   AGE
replicaset-nginx-out-5566fb554b                   Trivy     9d
replicaset-nginx-trivy-operator-test-6c69f7975c   Trivy     41d
service-kubernetes                                Trivy     10h
service-nginx-out-svc                             Trivy     10h
service-nginx-sample-svc                          Trivy     10h
service-nginx-service                             Trivy     10h

구조는 동일하게 report내 checks 항목에 위반된 각 ID별 스캔 결과가 확인되어진다.

jacob@laptop:~ $ kubectl get configauditreports replicaset-nginx-out-5566fb554b -o jsonpath='{.report.checks[]}' | jq
{
  "category": "Kubernetes Security Check",
  "checkID": "KSV016",
  "description": "When containers have memory requests specified, the scheduler can make better decisions about which nodes to place pods on, and how to deal with resource contention.",
  "messages": [
    "Container 'nginx-out' of ReplicaSet 'nginx-out-5566fb554b' should set 'resources.requests.memory'"
  ],
  "severity": "LOW",
  "success": false,
  "title": "Memory requests not specified"
}
jacob@laptop:~ $ kubectl get configauditreports replicaset-nginx-out-5566fb554b -o jsonpath='{.report}' | jq -r '.scanner, .summary'
{
  "name": "Trivy",
  "vendor": "Aqua Security",
  "version": "0.11.1"
}
{
  "criticalCount": 0,
  "highCount": 0,
  "lowCount": 11,
  "mediumCount": 3
}

동일하게 KSV로 시작되는 ID로 확인된 스캔 결과를 제공하며

jacob@laptop:~ $ kubectl get RbacAssessmentReport role-ingress-nginx -n ingress-nginx -o jsonpath='{.report.checks[]}' | jq
{
  "category": "Kubernetes Security Check",
  "checkID": "KSV041",
  "description": "Check whether role permits managing secrets",
  "messages": [
    "Role permits management of secret(s)"
  ],
  "severity": "CRITICAL",
  "success": false,
  "title": "Do not allow management of secrets"
}

아래와 같은 스캔결과를 확인할 수 있다.

jacob@laptop:~ $ kubectl get RbacAssessmentReport role-ingress-nginx -n ingress-nginx -o jsonpath='{.report}' | jq -r '.scanner, .summary'
{
  "name": "Trivy",
  "vendor": "Aqua Security",
  "version": "0.11.1"
}
{
  "criticalCount": 1,
  "highCount": 0,
  "lowCount": 0,
  "mediumCount": 0
}

6. exposedsecretreports

container image내에 secret이 발결된경우 이를 exposedsecretreport로 생성한다.

7. infraassessmentreports

intra 의 주요 구성요소들(etcd, apiserver, scheduler, controller-manager 등)의 설정에 대한 스캔 결과이다.

jacob@laptop:~ $ kubectl get InfraAssessmentReport -n kube-system
NAME                                                    SCANNER   AGE
service-kube-prometheus-stack-kube-controller-manager   Trivy     16d
service-kube-prometheus-stack-kube-etcd                 Trivy     16d
service-kube-prometheus-stack-kube-scheduler            Trivy     16d

8. rbacassessmentreports

설정 감사도구에 의해 스캔된 결과이다.

jacob@laptop:~ $ kubectl get RbacAssessmentReport -A -o wide
NAMESPACE                  NAME                                                     SCANNER   AGE    CRITICAL   HIGH   MEDIUM   LOW
default                    role-role-for-serviceaccount                             Trivy     25d    1          0      0        1
gatekeeper-system          role-gatekeeper-manager-role                             Trivy     19d    1          0      0        0
ingress-nginx              role-ingress-nginx                                       Trivy     9d     1          0      0        0
ingress-nginx              role-ingress-nginx-admission                             Trivy     9d     1          0      0        0
ingress-nginx2             role-ingress-nginx2                                      Trivy     9d     1          0      0        0
ingress-nginx2             role-ingress-nginx2-admission                            Trivy     9d     1          0      0        0
kube-public                role-b99d4b8d7                                           Trivy     41d    0          0      1        0
kube-system                role-565cd5fdf                                           Trivy     41d    0          0      0        0
kube-system                role-6fbccbcb9d                                          Trivy     41d    0          0      1        0
kube-system                role-77cd64c645                                          Trivy     41d    0          0      1        0
kube-system                role-79f88497                                            Trivy     41d    0          0      1        0
kube-system                role-868458b9d6                                          Trivy     41d    1          0      0        0
kube-system                role-addon-http-application-routing-nginx-ingress-role   Trivy     23d    1          0      1        0
kube-system                role-b99d4b8d7                                           Trivy     41d    1          0      0        0
kube-system                role-eraser-leader-election-role                         Trivy     31d    0          0      1        0
kube-system                role-extension-apiserver-authentication-reader           Trivy     41d    0          0      0        0
kube-system                role-policy-pod-agent                                    Trivy     33d    0          0      0        0
promstack                  role-kube-prometheus-stack-grafana                       Trivy     17d    0          0      0        0
testns                     role-role-for-serviceaccount                             Trivy     24d    1          0      0        0
trivy-system               role-trivy-operator                                      Trivy     41d    1          0      1        0
trivy-system               role-trivy-operator-leader-election                      Trivy     41d    0          0      0        0

9. vulnerabilityreports

kubernetes cluster의 workload 내에 container image 들중 최신의 취약점이 발견에 대한 리포트이다.
실제 생성된 report는 다음과 같이 확인되어진다.

jacob@laptop:~ $ kubectl get vulnerabilityreports replicaset-nginx-7f486b5585-nginx -o json
{
    "apiVersion": "aquasecurity.github.io/v1alpha1",
    "kind": "VulnerabilityReport",
    "metadata": {
        "annotations": {
            "trivy-operator.aquasecurity.github.io/report-ttl": "24h0m0s"
        },
        "creationTimestamp": "2023-02-19T09:15:01Z",
        "generation": 1,
        "labels": {
            "resource-spec-hash": "7f8f5d4bfb",
            "trivy-operator.container.name": "nginx",
            "trivy-operator.resource.kind": "ReplicaSet",
            "trivy-operator.resource.name": "nginx-7f486b5585",
            "trivy-operator.resource.namespace": "default"
        },
        "name": "replicaset-nginx-7f486b5585-nginx",
        "namespace": "default",
        "ownerReferences": [
            {
                "apiVersion": "apps/v1",
                "blockOwnerDeletion": false,
                "controller": true,
                "kind": "ReplicaSet",
                "name": "nginx-7f486b5585",
                "uid": "b6e4552e-c6b4-4e65-8829-60e89fc06251"
            }
        ],
        "resourceVersion": "525669",
        "uid": "ed074222-38b2-4161-bb9f-c32f708b84f1"
    },
    "report": {
        "artifact": {
            "repository": "library/nginx",
            "tag": "stable"
        },
        "registry": {
            "server": "index.docker.io"
        },
        "scanner": {
            "name": "Trivy",
            "vendor": "Aqua Security",
            "version": "0.37.2"
        },
        "summary": {
            "criticalCount": 0,
            "highCount": 0,
            "lowCount": 0,
            "mediumCount": 1,
            "noneCount": 0,
            "unknownCount": 0
        },
        "updateTimestamp": "2023-02-19T09:15:01Z",
        "vulnerabilities": [
            {
                "fixedVersion": "3.7.1-5+deb11u3",
                "installedVersion": "3.7.1-5+deb11u2",
                "links": [],
                "primaryLink": "https://avd.aquasec.com/nvd/cve-2023-0361",
                "resource": "libgnutls30",
                "severity": "MEDIUM",
                "target": "",
                "title": "A timing side-channel in the handling of RSA ClientKeyExchange message ...",
                "vulnerabilityID": "CVE-2023-0361"
            }
        ]
    }
}

해당 이미지의 저장소, repository, tag 그리고 이를 scan한 scanner 정보 등이 같이 출력되어지며 summary로 각 severity(심각도)별 count를 표현해준다. count에 맞는 수량의 발견된 취약점은 aquasec에서 제공하는 cve 정보와 함께 link로 제공되며 기본적인 title과 CVE 번호 등이 제공되어진다.

취약점 DB

container image에 대한 취약점 DB는 링크에 설명된 방식대로 확인 및 검색이 가능했다.

다만 아래와 같은 KSV로 시작되는 DB는 정확히 매칭되는 항목을 찾지는 못했다.
(예상하기론 위에 정리된 링크(https://avd.aquasec.com/) 상에서 찾아보면 매칭되는게 있기는할거 같은데 찾는방법은 좀더 확인이 필요해보인다.)

  - category: Kubernetes Security Check
    checkID: KSV048
    description: Check whether role permits update/create of a malicious pod
    messages:
    - Role permits create/update of a malicious pod
    severity: HIGH
    success: false
    title: Do not allow update/create of a malicious pod

Custom Policy 생성

ConfigAudit에서 사용되어지는 Policy를 REGO Language로 생성하여 사용할 수 있다.

이는 좀더 테스트가 필요하다.
... WIP ...

새로운 app 배포

배포후 (scan 수행에 약간의 시간이 소요되어지며 대략적)
다음과 같은 pod와 job이 수행되어지고

jacob@laptop:~ $ kubectl tree deploy nginx
NAMESPACE  NAME                                               READY  REASON  AGE
default    Deployment/nginx                                   -              117s
default    └─ReplicaSet/nginx-55bdcf7cbb                      -              117s
default      ├─ConfigAuditReport/replicaset-nginx-55bdcf7cbb  -              115s
default      └─Pod/nginx-55bdcf7cbb-pcpn7                     True           117s

확인된 clusterauditreport를 확인해보면 아래와 같이 ownerReferences metadata를 가지고 있다.

jacob@laptop:~ $ kubectl get ConfigAuditReport/replicaset-nginx-55bdcf7cbb -o jsonpath='{.metadata.ownerReferences}' | jq
[
  {
    "apiVersion": "apps/v1",
    "blockOwnerDeletion": false,
    "controller": true,
    "kind": "ReplicaSet",
    "name": "nginx-55bdcf7cbb",
    "uid": "6477c17f-a437-4fb4-bc04-ca3d1c3d73ef"
  }
]

trivy scan job

실제 trivy image scan을 하는 job을 확인해보면 initcontainer로 db를 가져오고 trivy-operator-trivy-config를 기반으로 initcontainer로 다운받은 db를 cache-dir을 통해 로드하여 trivy image scan을 수행하는것을 볼수 있다.

jacob@laptop:~ $ kubectl get job scan-vulnerabilityreport-64d95b5978 -n trivy-system -o jsonpath='{.spec.template.spec.containers}' | jq
[
  {
    "args": [
      "-c",
      "trivy image --slow 'quay.io/prometheus/prometheus:v2.39.1' --scanners vuln,secret --cache-dir /tmp/trivy/.cache --quiet --skip-db-update --format json > /tmp/scan/result_prometheus.json &&  bzip2 -c /tmp/scan/result_prometheus.json | base64"
    ],
    "command": [
      "/bin/sh"
    ],
    "env": [
      {
        "name": "TRIVY_SEVERITY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.severity",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_IGNORE_UNFIXED",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.ignoreUnfixed",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_OFFLINE_SCAN",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.offlineScan",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_TIMEOUT",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.timeout",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_FILES",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipFiles",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_DIRS",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipDirs",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTP_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTPS_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpsProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "NO_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.noProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      }
    ],
    "image": "ghcr.io/aquasecurity/trivy:0.38.2",
    "imagePullPolicy": "IfNotPresent",
    "name": "prometheus",
    "resources": {
      "limits": {
        "cpu": "500m",
        "memory": "500M"
      },
      "requests": {
        "cpu": "100m",
        "memory": "100M"
      }
    },
    "securityContext": {
      "allowPrivilegeEscalation": false,
      "capabilities": {
        "drop": [
          "ALL"
        ]
      },
      "privileged": false,
      "readOnlyRootFilesystem": true
    },
    "terminationMessagePath": "/dev/termination-log",
    "terminationMessagePolicy": "FallbackToLogsOnError",
    "volumeMounts": [
      {
        "mountPath": "/tmp",
        "name": "tmp"
      },
      {
        "mountPath": "/tmp/scan",
        "name": "scanresult"
      }
    ]
  },
  {
    "args": [
      "-c",
      "trivy image --slow 'quay.io/prometheus-operator/prometheus-config-reloader:v0.60.1' --scanners vuln,secret --cache-dir /tmp/trivy/.cache --quiet --skip-db-update --format json > /tmp/scan/result_config-reloader.json &&  bzip2 -c /tmp/scan/result_config-reloader.json | base64"
    ],
    "command": [
      "/bin/sh"
    ],
    "env": [
      {
        "name": "TRIVY_SEVERITY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.severity",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_IGNORE_UNFIXED",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.ignoreUnfixed",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_OFFLINE_SCAN",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.offlineScan",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_TIMEOUT",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.timeout",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_FILES",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipFiles",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_DIRS",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipDirs",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTP_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTPS_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpsProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "NO_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.noProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      }
    ],
    "image": "ghcr.io/aquasecurity/trivy:0.38.2",
    "imagePullPolicy": "IfNotPresent",
    "name": "config-reloader",
    "resources": {
      "limits": {
        "cpu": "500m",
        "memory": "500M"
      },
      "requests": {
        "cpu": "100m",
        "memory": "100M"
      }
    },
    "securityContext": {
      "allowPrivilegeEscalation": false,
      "capabilities": {
        "drop": [
          "ALL"
        ]
      },
      "privileged": false,
      "readOnlyRootFilesystem": true
    },
    "terminationMessagePath": "/dev/termination-log",
    "terminationMessagePolicy": "FallbackToLogsOnError",
    "volumeMounts": [
      {
        "mountPath": "/tmp",
        "name": "tmp"
      },
      {
        "mountPath": "/tmp/scan",
        "name": "scanresult"
      }
    ]
  },
  {
    "args": [
      "-c",
      "trivy image --slow 'quay.io/prometheus-operator/prometheus-config-reloader:v0.60.1' --scanners vuln,secret --cache-dir /tmp/trivy/.cache --quiet --skip-db-update --format json > /tmp/scan/result_init-config-reloader.json &&  bzip2 -c /tmp/scan/result_init-config-reloader.json | base64"
    ],
    "command": [
      "/bin/sh"
    ],
    "env": [
      {
        "name": "TRIVY_SEVERITY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.severity",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_IGNORE_UNFIXED",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.ignoreUnfixed",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_OFFLINE_SCAN",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.offlineScan",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_TIMEOUT",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.timeout",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_FILES",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipFiles",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "TRIVY_SKIP_DIRS",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.skipDirs",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTP_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "HTTPS_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.httpsProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      },
      {
        "name": "NO_PROXY",
        "valueFrom": {
          "configMapKeyRef": {
            "key": "trivy.noProxy",
            "name": "trivy-operator-trivy-config",
            "optional": true
          }
        }
      }
    ],
    "image": "ghcr.io/aquasecurity/trivy:0.38.2",
    "imagePullPolicy": "IfNotPresent",
    "name": "init-config-reloader",
    "resources": {
      "limits": {
        "cpu": "500m",
        "memory": "500M"
      },
      "requests": {
        "cpu": "100m",
        "memory": "100M"
      }
    },
    "securityContext": {
      "allowPrivilegeEscalation": false,
      "capabilities": {
        "drop": [
          "ALL"
        ]
      },
      "privileged": false,
      "readOnlyRootFilesystem": true
    },
    "terminationMessagePath": "/dev/termination-log",
    "terminationMessagePolicy": "FallbackToLogsOnError",
    "volumeMounts": [
      {
        "mountPath": "/tmp",
        "name": "tmp"
      },
      {
        "mountPath": "/tmp/scan",
        "name": "scanresult"
      }
    ]
  }
]

배포된 pod 기반으로 다음과 같은 scan 결과를 확인할 수 있다.

jacob@laptop:~ $ kubectl get vuln replicaset-nginx-trivy-operator-test-6c69f7975c-nginx -o jsonpath='{.report.vulnerabilities[0]}' | jq
{
  "fixedVersion": "1.8.2.2",
  "installedVersion": "1.8.2",
  "links": [],
  "primaryLink": "https://avd.aquasec.com/nvd/cve-2020-27350",
  "resource": "apt",
  "score": 5.7,
  "severity": "MEDIUM",
  "target": "",
  "title": "apt: integer overflows and underflows while parsing .deb packages",
  "vulnerabilityID": "CVE-2020-27350"
}

CVE 와 그에 맞는 간단한 설명 그리고 aquasecurity에서 작성한 link를 제공하고 있어 이를 기반으로 확인이 가능하다.

monitoring integration

webhook으로 취약점 리포트를 slack과 같은 도구로 전달할 수 있다.
Aquasecurity에서 개발 및 opensource 화한 postee를 이용하도록 되어 있고 postee를 이용한 방식 및 결과는 다음 링크에 정리해두었다.

trivy-operator의 deployment에서 아래와 같은 환경변수 수정 진행한다.
(http://와 같은 scheme를 필히 입력해주어야 한다.)

        - name: OPERATOR_WEBHOOK_BROADCAST_URL
          value: http://postee-svc.default.svc.cluster.local:8082
        - name: OPERATOR_WEBHOOK_BROADCAST_TIMEOUT
          value: 30s

postui에서 trivy-operator-slack template을 아래 링크로 추가한뒤

vulnerabilityreport가 생성되면서 아래와 같이 postee에서 event가 확인되어진다.
아래와 같은 postee 로그가 확인되어지면 slack을 통한 메세지가 출력되어진다.

postee 2023/04/03 11:14:12 Sending via Slack "jacob-slack"
postee 2023/04/03 11:14:13 Sending [1/1 part] to "jacob-slack" was successful!
postee 2023/04/03 11:14:13 Sending [1/1 part] to "jacob-slack" was successful!

아래는 실제 slack 으로 출력된 취약점 report의 결과이다.

prometheus and grafana

trivy-operator로 생성된 report들을 grafana의 dashboard로 visualize하게 확인할 수 있다.
기본적으로 trivy-operator에서 exporter를 제공중이며 이를 prometheus에서 수집하도록 하고 grafana로 visualize 하게 dashboard를 만들어 보여주게 된다. 아래 링크에서 grafana-dashboard에 대한 내용이 언급되어 있다.

trivy-operator가 설치되어 있는 cluster에 prometheus와 grafana가 구성하고
간단하게 prometheus 에 additionalscrapconfigs에 아래와 같은 job을 추가하여 prometheus에 metric을 수집하도록 하였다.

    additionalScrapeConfigs:
    - job_name: 'trivy-operator'
      static_configs:
      - targets:
        - trivy-operator.trivy-system.svc.cluster.local:8080

실제 수집되는 데이터는 아래 metrics 에서 소개된 trivy_image_vulnerabilities/trivy_resource_configaudits/trivy_exposedsecrets_info/.... 등이 확인되어진다.

prometheus에서 위 metric들이 수집된것이 확인되면 다음 dashboard(id : 16652)를 grafana에 import 하고

아래와 같은 dashboard를 생성하여 severity별 count 및 chart를 확인할 수 있다.

개인적인 생각 정리

다음과 같은 항목에 대한 고민이 필요할 것으로 보인다.

  • report를 문서화 시켜야하는 부분 (pdf와 같이 이는 postee에서 다른 platform (ex. splunk 같은)을 통한 연동으로 해결이 되는지는 확인해봐야할것 같다.) 
  • webhook과 prometheus 로의 데이터 전송이 가능하기에 이를 어떻게 활용하여 알람 혹은 모니터링을 할 수 있을지
    (slack, teams 등의 메신저, email 그리고 prometheus 를 통한 alertmanager 활용 등 다양한 방식이 존재하기에 이를 자신의 서비스에 어떻게 잘 맞출지 고민을 먼저 해볼 필요가 있어보인다.) 
  • 실질적으로 보안이슈를 고쳐주지는 못하기에 이에 인지를 위한 platform이고 이에 대한 조치를 어떻게 해야할지
    (postee에서 exec action 등을 통해 이를 해결할수 있다고 하는데 좀더 확인이 필요해보인다.) 

하나의 cluster를 다양한 관점에서 scan 하여 report를 제공해주기 때문에 cluster 전반에 대한 보안complaince를 제공할수 있다. 또한 이를 webhook과 같은 알람 및 prometheus 연동을 통한 grafana 모니터링이 가능하기에 이를 잘 활용한다면 보안에 대한 관리를 최소화하면서도 최대의 효과를 가져올수 있지 않을까 조심스레 생각해본다.

테스트를 진행하면서 정리한 내용들로 실제 동작되는 설정과 다르게 정리된게 있을수 있습니다.
관련해서 답글 주시면 업데이트 해볼 예정입니다.

'Cloud > Kubernetes' 카테고리의 다른 글

Gatekeeper monitoring and logging  (0) 2023.05.26
Eraser (Image cleaner)  (0) 2023.04.25
Postee  (0) 2023.03.17
kubent(no trouble)  (0) 2023.03.14
Vertical Pods Autoscaler  (0) 2023.02.16
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함