23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
Kubernetes 보안 연재를 마무리를 어떤 주제로 마무리해야 하나 고민 했다.
사실 필자는 Policy란 조금은 모호한 주제를 선택했고 앞으로 기술할 내용도 Policy에 대한 것 이다.
하지만 Policy는 너무 광의에 뜻 이지 않은가? 이글을 쓰는 의도를 좀더 분명하게 전달 할 수 있는 제목이 필요했다.
고민 끝에 크게 내키지는 않지만 DevSecOps란 Keyword를 사용하기로 했다. (사실 필자는 세상의 Buzz word를 극도로 싫어한다.
물론 Cooking을 위해서 필요한 일인 건 맞지만 코에 걸면 코걸이 귀에 걸면 귀걸이로 변질 되면서, 수많은 숙제만 양산하기에 때문이다.)
여하튼, 마지막 주제는 DevSecOps다. 땅땅땅
다소 과격한 표현이지만, DevOps 더 나아가서 DevSecOps 등이 중요해 지는 이유는 무엇일까?
이런저런 이야기가 많지만 대 부분 DevOps던 Agile던 Micro Service던 지향점은 빠르고/자주 SW를 Update하는 것 이다.
하지만 이는 빠르다는 기준이 1년에 한번인지 하루에 한번인지에 따라 다를 뿐이자, Hardware가 아닌 Software가 태생적으로 갖는 특징이지 않은가?
즉 그닥 새로울 것이 없는 것 이다. 그렇다면 이 시기에 왜 이리 시끄러운 것 일까?
지금 부터는 필자의 개인적인 생각을 풀어 보겠다. 개인적인 생각이니 만약 필자의 생각과 다르다고 생각되면 빠르게 지나쳐가시면 된다.
주의!! 결코 두 회사에 대해서 좋고 나쁨을 이야기하는 것이 아니다. 워낙 대표적인 회사라서 언급한다.
우리 모두가 알고 있듯이 Computer Science (잘 생각해 보면 이름도 요상하다 -_-;)에 Terminology라는게 명확히 정의하기가 어렵다.
사실 SW는 특정 목적으로 개발되었지만 쓰는 사람이 그 용도를 변경 할 수도 있고, 과거 그 무언가에 영감을 받을 수 있었으나,
결국 개발자 개인의 초자아(?)에 따라 우리가 생각한 것과는 조금씩 다른 그 무언가로 완성되고, 또 누군가의 손에 의해서 끊임없이 변화하기 때문이다.
IT(Information Technology)란 과거 하버드 비즈니스 스쿨에서 처음 쓴 용어라고 위키피디아 어딘가에서 본 적이 있다.
그 당시 IBM이 출퇴근 여부를 자동으로 체크하는 출퇴근 카드 시스템을 만들었다고 한다.
이것을 본 똘똘이 선배님이 "아~~ 미래에는 Business의 본질에 사람은 집중하고, 그외 기타 운영을 도와주는 것 들이 많이 나올거야... 우린 그것을 정보기술 이라 부르자고" 라고 기술 했다.
즉 IT의 기원, 본 글에서의 IT는 특정 사업을 지원하는 사업지원 시스템을 의미한다.
과거 Fax / 인터폰 등이 대표적 이었고 최근에는 ERP, 근태관리 등이 대표적이다. 특히 컴퓨터/스마트폰의 보급으로 HW기반 정보기술은 SW기반 정보 기술로 바뀐지 오래다.
따라서 많은 과거 선배 개발자들은 IBM과 같은 SW Solution 을 만드는 회사에서 물건을 만들고 납품을 하는 B2B 시장 SI 시장에서 많이 일했다.
하지만 Google이 나타나면서 큰 변화가 생기게 되었다. 과거 SW는 B2B 혹은 Game용이 대부분 이었는데,
Google / Facebook 과 같이 B2C를 대상으로 하는 서비스를 직접 구축하는 업체들이 대두되기 시작한 것이다.
심지어 Apple이나 Tesla와 같이 HW를 파는 업체들의 경쟁력중 SW의 비중이 높아지면, 개발자들이 갈 업체가 확 늘어난 것 이다.
여기서 현실적인 이야기를 해 보자. 사장이 아닌 개발자 입장에서 본인의 서비스를 직접개발하는 회사에서 일하고 싶은가? 아니면 SI를 하고 싶은가?
MSA를 보면 필자가 느낀것은 이전 Micro Kernel과 Monolic Kernel의 싸움이 생각났다.
또한 Distributed System과 Centralized System의 대결도 생각났다. RISC와 CISC도 생각나더라.
이들의 공통점이 무엇일까? 필자는 모듈화를 통한 개별적 발전의 신속성과 집중화를 통한 최적화에 대한 것 이라 생각한다.
(이또한 필자의 개인 의견이다. 자꾸 개인의견임을 명확히 하는 것은 남의 말을 옮기며 가정이 가정의 근거가되는 내 생각이 없는 비겁한 이 사회에 대한 분노가...마침네...)
지금 그렇다면 모듈화를 통해 개발적 발전(쉽게 말하면 난 모르겠고 내일만 정확히 하면되게 해죠.)이 중요해진 이유에 대해서 고찰해 봤다.
Google과 같은 서비스업체의 등장으로 개발자들이 대거 이동했기 때문에, SI Biz에서는 개발자 모으기가 어려워졋기 때문이다.
또한 Google과 같은 서비스 업체가 늘어나면 서비스업체간 개발자의 이동도 빈번하니 새로운 개발자 풀이 기존의 룰 및 Legacy에 종속되지 않게
(즉, 러닝커브를 줄여 바로 투입할수 있게)하기 위해서 MSA는 매우 매력적이다. MSA의 육각형은 구현이 없으면 사랑은 러브와 같은 공허한 외침일 뿐이다.
하지만 Kuberentes를 통해 정말 독립적이면서 저화로운 육갹형(오각형인가?)를 구현할 수 있게 되었다.
여러팀이 다른 팀의 환경에 종속적이지 않으면서도 Common한 OAM 체계를 유지 할 수 있는 Kubernetes를 통해 MSA가 실현될 수 있었다.
하지만 환경에 대한 제어가 안되니 여러 보안 이슈가 발생 할 수 있고 몇몇 빌런들이 자원을 독점하는 등, 나만 잘되면 그만 정신이 스믈스믈 자라나기 쉽다.
따라서, MSA로 구성되는 시스템을 구축하는 팀간은 무엇가 약속이 필요하다. 보통 이 약속을 강제하고 수립하는 것을 Governance라 한다.
그럼 이 Governance를 어떻게 실현 할 것 인가? 크게 두 방향이 있다.
첫번째는 Code, 즉 행동강령이다.
두번째는 Constraint, 즉 하지말 것을 정하는 것 이다.
Governance를 자동으로 제어하려면 Constraint를 사용 할 수 밖에 없다.
하지만 필자는 언어가 주는 무서움(?) 때문에 Policy란 표현을 쓴다.
더 풀어 쓰자면 하지말아야할 것에 대한 정책이다.
DevOps는 이런 저련 고차원적인 이야기가 있겠지만, 결국은 CI/CD 더 쉽게 말하면 Jenkins로 대표되는 SW의 설치 변경에 대한 자동화다.
즉 Dev가 개발하고 Ops가 설치/운영하는 데, 이를 시스템화 한 것 이다.
따라서 CI/CD pipeline도 기본적인 Build --> Deploy 사이에 여러가지 Test / Verification이 들어간다.
이 Test / Verification 의 목적은 하지말아야 할 것들을 걸러내서 최종적으로 Deploymemt를 막는 것 이다. 즉 CI/CD Policy가 이미 들어가 있는 것 이다.
요즘 Sec 중요한 이유는 워낙 다양한 OpenSource를 사용하기 때문에 Verification 단계에 Open Source에 대한 검증도 매우 중요해 졌고,
과거 B2B가 아닌 B2C 서비스 비중이 늘면서 개인정보 탈취에 대한 우려가 더 커졌기 때문이다.
여기서 Kubernetes의 아름다움을 발견 할 수 있다. 1,2,3편에서 이야기 했듯이, 극단적으로 말하면 Kubernetes는 REST API다.
Kubernetes에 SW를 배포하고 관리하고 네트워크를 설정하는 그 모든 것이, 하다 못해 설정을 저장하고 Credential를 관리하고 Storage를 사용하는 그 모든 것이 REST API롤 통한다.
따하서 Kube API Server가 제공하는 Admission webook를 통해서 모든것을 검증하고 변경할 수 있다.
따라서 Governance 확보를 통해 개발팀이 독립적으로 자유롭게 개발하면서 의도했던 더 문제되는 의도치 않은 잘못(즉 시스템이 되서 했는데 잘못을하는 경우)을 사전에 막아서
혁신의 속도를 높이기 위해서는 Kubernetes Admission Control를 사용하는 것이 가장 좋은 방법이다.
Admission Webhook을 이용한 Governance 확보가 중요해 지면서 Kubernetes 1.30 부터 Stable로 들어간 Kubernetes Built-in Controller다.
PSP를 Deplicated 시킬때랑 조금 다르잖아라고 생각하는 건 필자의 유연하지 못한 생각 때문일거다^^. 앞서 말했듯이 변하는 거다. 사랑도 정의도.
Kubernetes는 Admission에 대한 요구가 강해지면서, 자체적으로 Programmable하게 Policy를 작성할 수 있는 수단을 Validating Admission Policy를 통해 제공한다.
Kubernetes 공식 문서에서도 Validating Admission Policy를 webhook를 이용한 Admission 검증의 대안이라 소개하고 있다.
Validating Admission Policy는 CEL(Common Expression Language)을 사용하여 정책 검증 규칙을 선언합니다.
CEL이라는 언어를 사용함으로 다양한 정책을 코딩 가능하다. 또한 관리자의 필요에 따라 매개변수화 및 리소스 범위 지정이 가능한 정책을 정의할 수 있다.
이는 3rd party solution인 OPA Gatekeeper의 특징과 유사하다. OPA Gatekeeper는 뒷절에서 좀더 자세히 다룬다.
[참고]https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/
Validating Admission Policy는 3개의 자원으로 구성된다.
ValidatingAdmissionPolicy
CEL로 표현되는 검증 대상과 검증식을 정의한 리소스다.
예를 들어 Greedy한 자원할당을 요구시(e.g. 6개 이상 replica 생성) 검증 실패
ValidatingAdmissionPolicyBinding
생성한 Policy를 적용할 대상을 선정하고 검증 실패시 동작을 정의한다.
예를 들어 특정 Namespace에 속한 pod에 대해서 정책을 적용
Parameter
CEL로 작성된 검증식에 추가하는 변수
ValidatingAdmissionPolicy의 spec.paramKind에 선언됨
예를 들어 Greedy한 자원 할당의 기준
아래는 예제다.
replicalimit-policy.example.com이라는 정책을 정의 한다.
kubernetes deployment 리소스의 생성과 업데이트 요청 시, params.maxReplicas 이 넘으면 admission fail로 판단하는 정책이다.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "replicalimit-policy.example.com"
spec:
failurePolicy: Fail
paramKind: ## ReplicaLimit 라는 자원을 변수로 선언
apiVersion: rules.example.com/v1
kind: ReplicaLimit
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= params.maxReplicas" ## 변수를 가지고 검증식생성
reason: Invalid 변수 자원을 별도로 생성한다.
paramKind에 정의한 것과 같이, resource를 생성한다. 여기서는 최대 Replica수를 3으로 설정한다.
apiVersion: rules.example.com/v1
kind: ReplicaLimit
metadata:
name: "replica-limit-test.example.com"
namespace: "default"
maxReplicas: 3이제 정책을 적용할 대상을 설정한다.
spec.paramRef 에 사용할 변수 자원을 지정한다. test란 label를 갖는 namespace의 deployment 중 replica 가 4이상인 경우, 생성/업데이트를 Deny하는 정책이 실시 된다.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "replicalimit-binding-test.example.com"
spec:
policyName: "replicalimit-policy.example.com"
validationActions: [Deny]
paramRef:
name: "replica-limit-test.example.com"
namespace: "default"
matchResources:
namespaceSelector:
matchLabels:
environment: test하나의 Policy에 다수의 PolicyBinding이 존재 할 수 있고, 각 PolicyBinding은 독립적인 Parameter를 사용 할 수 있다.
OPA(Open Policy Agent) Gatekeeper는 Microsoft나 Google과 같은 Global 업체가 Kubernetes Admission webhook controller로 사용 하고 있는 가장 대표적으로 역사가 오래된 기술 이다.
OPA Gatekeeper는 OPA라는 기반 Kubernetes에 최적된 Solution 이다.
이미 널리 쓰여지고 있는 기술로 필요한 정책들이 미리 개발되어 공유되고 있다.
Community policy library : https://open-policy-agent.github.io/gatekeeper-library/website/
OPA Gatekeeper는 OPA를 기반으로 Kubernetes에 최적화해서 제공하는 Kuberentes Admission Controller다.
Kubernetes API Server를 대상으로 하는 정책 엔진이기 때문에, 이미 잘 정의된 Domain이다. 따라서 모두가 쓸 수 있는 Framework을 구축할 수 있다.
또한 Interface 측면에서도 Kubernetes API 자체가 Well-defined webhook interface를 제공하기 때문에 Kubernet API Server의 변경 없이,
OPA Gatekeeper가 webhook interface를 지원함으로 연동을 명확하고 간결하게 할 수 있다.
가장 중요한 부분은 정책의 배포다. Admission Policy는 고정되는 것이 아니라 시기와 상황에 따라 계속 바뀌고 진화해야 한다.
따라서 손쉬운 정책 배포와 관리가 필수 적이다. Kubernetes는 Custom Resource를 생성할 수 있다.
이는 Kubernetes가 제공하는 기본 Resource외 사용자 정의 자원을 정의하고 해당 자원에 대한 Life-cycle를 관리할 수 있는 Scheduler를 Controller란 이름으로 제공 누구나 쉽게 설치 할 수 있다.
단순히 Spec을 정의를 넘어, 이미 검증된 Operator Library(e.g. client.go)들을 제공하고 있다.
마지막으로 OPA 가 제공하지 않고 있던 HA(High Availability)는 Kubernetes의 Service 자원으로 제공 한다.
OPA Gatekeeper는 Kubernetes위에 설치되는 Controller로 Kubernetes Cluster마다 설치된다. 즉 분산되어 설치된다.
또한 Kubernetes Service를 통해 Redundancy를 지원하며, Policy를 모두 Kubernetes CR(Custom Resource)형태로 관리함으로 별도 Database가 필요없이,
Kubernetes가 제공하는 etcd를 활용한다. 따라서 kubectl과 같은 Kubernetes가 제공하는 기본 Tool를 사용하여 손쉽게 정책을 생성/관리/배포 가능하다.
OPA Gatekeeper는 크게 2가지 구성요소로 구현되어 있다.
OPA Gatekeeper Controller
CR로 생성된 정책을 관리한다.
Admission webhook으로 온 Admission 요청을 정책에 따라 검사한다.
OPA Gatekeeper Aduit
Admission webhook은 생성/삭제/변경 요청시에 동작한다. 따라서 정책이 적용되기전 생성된 자원에 대해서는 감시 할 수 없다.
따라서 OPA Gatekeeper는 Audit agent를 통해 주기적으로 이미 생성된 자원에 대한 감사로그를 작성하여 운영자로 정책이 미적용된 자원에 대한 처리를 도와 줄 수 있다.
OPA Gatekeeper는 2가의 Custom Resource를 통해 정책을 적용한다.
ConstraintTemplate
Validating Admission Policy의 ValidatingAdmissionPolicy 자원과 같은 개념이다.
다른점은 Parameter를 OpenAPIV3 format으로 관리하고, CEL이 아닌 Rego 언어로 Validation logic을 표현한다.
Constraints
Validating Admission Policy의 ValidatingAdmissionPolicyBinding 자원과 같은 개념이다. 즉 정책이 적용될 대상을 한정하는 자원이다.
OPA Gatekeeper는 parameter 값을 를 constraint에 embeded 시킨이다. 이는 Validating Admission Policy에 비해 아쉬운 부분이다.
즉 다양한 정책에 공통적으로 적용될 전역 변수 설정이 불가하고 개별설정을 해야 하기 떄문에 오류가능성이 존재한다.
예제를 통해 동작을 파악해 보자.
아래는 ContraintTemplate의 예다. Template를 통해 K8SReuiredLabel이라는 Contraint를 생성하는 것을 Spec.에 명시하고 있다.
paramter는 Lables 란 이름의 array string으로 정의하고, tagets에 rego언어로 parameter로 입력받은 Label이 모두 존재하지 않으면 Admission fail을 정의한다.
Validating Admission Policy와 다른게 ConstraintTemplate에 Target resource를 명시하지 않는다.
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
# Schema for the `parameters` field
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: 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])
}예제의 Template를 생성하면, k8srequiredlabels.constraints.gatekeeper.sh 이란 crd가 자동으로 생성된다. 이는 추후 constraints를 생성하기 위해 crd다.
아래는 constraints 예이다. constraints에서 target resource와 parameter를 모두 입력 받는다.
즉, namespace 리소스에 대해서 gatekeeper라는 label이 없으면 생성/변경이 거부된다.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["gatekeeper"]아래와 같은 Error가 발생된다.
$ kubectl create ns test
Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [ns-must-have-gk] you must provide labels: {"gatekeeper"}OPA Gatekeeper는 배포된 자원들을 정기적으로 감시해서, 생성된 constraints를 위반하는지를 확인하합니다.
audit 결과는 각 constraints 의 status에 저장된다.
아래는 예제다.
앞에서 언급한 constraints의 status가 update된 예다.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
..
..
status:
auditTimestamp: “xxxx-xx-xxxxx:xx:xxx”
byPod:
- enforced: true
id: gatekeeper-controller-manager-0
violations:
- enforcementAction: deny
kind: Namespace
message: 'you must provide labels: {"hr"}'
name: default
..audit기능은 감시할 Resource의 duplication을 생성하여 실시 된다.
따라서 자원을 복제 할 수 있는 권한을 설정해야 하며, 이는 config 자원을 통해 설정합니다.
아래 예는 pod와 namespace 에 대한 복제를 허용하는 설정이다.
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: "gatekeeper-system"
spec:
sync:
syncOnly:
- group: ""
version: "v1"
kind: "Namespace"
- group: ""
version: "v1"
kind: "Pod"참고: 이건 부록이다. 우리는 일하다 보면 이런 비교를 강요 당한다. 그래서 준비했다.
OPA Gatekeeper의 등장으로 본격적으로 Kubernetes의 Admission Control리 주목 받으면서 Kubernetes 자체적으로 Validating Admission Policy를 제공한다.
두 기술은 그 목적 및 컨샙 및 사용 방식이 거의 유사하다.
물론 미세하게 보면 Rego 보다 CEL이 더 직관적인 점, Parameter 자원을 분리한점, Build-in 기능으로 별도 Webhook를 거치지 않는 점등 더 최신 기술이 당연히 갖는 장점이 존재한다.
하지만 SW는 계속 변경되기에 현 기준 두 기술에 대해서 간략히 비교한다.
위 표는 단순한 비교일 뿐, 이 표를 기준으로 어떤 기술을 선택할 수 있는 것은 아니다.
당연히 OPA Gatekeeper가 오래 검증된 기술임으로 좀더 풍부한 기능을 제공하는 것이고,
표에는 나타나 있지 않지만 Validating Admission Policy는 최신 기술인 만큼 Legacy의 아쉬운 부분이 보완되어 나온 것 이다.
대표적인 것인 Learning curve가 큰 Rego 대신 보단 직관적인 CEL를 쓴다는 것 이다.
현재로는 Validating Admission Policy가 Kubernetes가 자체적으로 제공하는 기능임으로 많은 기대를 받고 있지만,
1.30 version(2024)에 stable로 release되어 있고, 아직은 default로 on된 feature가 아니기에 유망주 정도로 보면 될 듯 하다.
또한 OPA Gatekeeper 또한 Rego 언어에 대한 장벽때문에 CEL 를 추가 지원할 계획이기 때문에, 좀더 지켜볼 필요가 있다.
국힙원탑 민*진님의 파랑모자는 못 쓸것 같아, 마무리는 조금 재미있게 마무리 하고자 했다.
필자는 Kubernetes governance란 주제하에 정리하다가 본 1,2,3,4편의 연재를 기획 했다. 누군가 모두를 합쳐서 정리한 내용은 없어서 정리해 봤는데 도움이 되었으면 한다.
마지막으로 필자가 생각한 메모로 끝 마무리한다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.