23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
클라우드 네이티브 애플리케이션의 근간이 되는 MSA는 각 서비스들의 독립성과 자율성을 최대한 보장함으로 권한 관리를 포함한 정책적인 측면은 중앙의 통제와 조율이 반드시 필요하다. 정책은 권한을 포함하는 보다 포괄적인 개념이며 궁극적으로는 전체 거버넌스를 통제하는 핵심이다.
정책을 범용 프로그래밍 언어 코드로 작성하면 변경 관리가 어려우며, 설정 파일이나 데이터베이스로 작성한다면 그 자체가 수동적이고 별도의 처리가 필요하다. Policy as Code는 이러한 점을 절충하기위해 고수준의 정책 전용 언어를 통해 정책을 작성하고 관리하는 방법이다. MSA 관점에서 본다면 Policy as Code는 정책이라는 중요하고 특별한 도메인을 담당하는 기술이라고 할 수 있다.
정책을 코드로 표현하도록하는 툴은 주요 소프트웨어 회사들을 중심으로 여럿 존재했으나 현재는 OPA라는 플랫폼이 이 분야의 강자로 떠오르고 있다. 본 블로그에서는 OPA에 대해 살펴보고자 한다.
OPA(Open Policy Agent)는 정책을 결정하는 부분과 수행하는 영역을 분리하기위해 시작되었고, 전체 시스템에 걸쳐 통합된 상황에 따른 정책 시행을 가능하게 하는 오픈 소스 범용 정책 엔진이 되었다. OPA는 현재 CNCF의 졸업 프로젝트(graduated project)로 클라우드 네이티브 정책의 사실상 표준으로 자리잡고 있다. 실제로 넷플릭스, 핀터레스트, 골드만삭스 등에서 쿠버네티스 및 마이크로서비스에 대한 정책엔진으로 사용되고 있으며 아틀라시안 제품군이나 Chef에도 포함되어있다.

OPA는 정책 및 데이터에 대한 질의를 평가하여 정책의 결정을 돌려준다. 여기에서 질의(Query)와 결정(Decision)은 json으로 표현하면 어떤 것이든 포함할 수 있으며 이에따라 매우 큰 확장성을 갖는다.
정책은 전용 언어(Rego)를 사용하여 기술하는데 도메인에 제한 받지 않는 (거의) 모든 종류의 정책의 기술이 가능하다.
질의의 예는 다음과 같다.
어떤 사용자가 어떤 리소스에 액세스할 수 있는가?
어떤 서브넷에 외부통신이 허용되는가?
어떤 클러스터로 워크로드를 배포해야 할 것인가?
어떤 레지스트리로부터 바이너리를 다운로드할 수 있는가?
어떤 OS 기능이 컨테이너와 함께 실행되는가?
어떤 시간에 시스템에 접근할 수 있는가?
결정도 단순 '예/아니오' 뿐 아니라 임의의 구조화된 데이터를 출력으로 사용할 수 있다.
데이터는 Json 형태로 저장되며 OPA 서버는 정책(Policy)을 기반으로 판단하는데 질의와 함께 이 데이터를 활용하여 결정을 만든다.
가상 환경을 정의하고 이 환경에서 OPA가 사용되는 시나리오를 통해 OPA를 더 구체적으로 이해해 보자.
본 단락에서는 입력데이터를 만드는 구체적인 예를 보여준다. 다음 그림과 같은 시스템이 있다고 가정하자.
0 개 이상의 프로토콜을 받는 서버들이 존재 (X,... Y, Z..)
공용이나 사설망에 서버들을 연결하는 네트워크 (public, .... private)
네트워크에 서버를 연결시키는 포트 (A, ... X, Y,.... Z)

이를 더 구체적으로 정의해 보자.
.png)
위 시스템은 다음과 같이 json으로 표현할 수 있고 이후 설명에서 입력데이터로 사용할 것이다.
{
"servers": [
{"id": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p2", "p3"]},
{"id": "db", "protocols": ["mysql"], "ports": ["p3"]},
{"id": "cache", "protocols": ["memcache"], "ports": ["p3"]},
{"id": "ci", "protocols": ["http"], "ports": ["p1", "p2"]},
{"id": "busybox", "protocols": ["telnet"], "ports": ["p1"]}
],
"networks": [
{"id": "net1", "public": false},
{"id": "net2", "public": false},
{"id": "net3", "public": true},
{"id": "net4", "public": true}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net3"},
{"id": "p3", "network": "net2"}
]
}여기에서 아래와 같은 요구사항이 있고 이에따라 정책을 적용해야한다고 가정하자.
1. 인터넷에서 접속가능한 서버들은 http를 노출해서는 안됨
2. 모든 서버들은 telnet을 노출해서는 안됨이를 rego를 사용하여 정의하면 다음과 같다. 라인별 내용은 주석을 통해 확인하자. rego의 구체적인 사용법은 공식 문서(https://www.openpolicyagent.org/docs/latest/policy-language/)를 참조할 수 있다.
package example
default allow = false # 기본적으로 허용되지 않는다.
allow = true { # 위반이 하나도 없다면 허용한다.
count(violation) == 0
}
violation[server.id] { # 서버는 다음의 경우에 위반
some server # 모든 서버를 대상으로
public_server[server] # public_server 함수가 를 통해 설정되어 있거나
server.protocols[_] == "http" # http 프로토콜을 포함하고 있다면
}
violation[server.id] { # 서버는 다음의 경우에 위반 (앞의 룰과 or조건)
server := input.servers[_] # input에 있는 모든 서버들에 대해
server.protocols[_] == "telnet" # telnet 프로토콜을 포함하고 있다면
}
public_server[server] { # 서버가 public에 연결되었는지 체크
some i, j
server := input.servers[_] # input에 있는 모든 서버를 대상으로
server.ports[_] == input.ports[i].id # 모든 포트들의 id를 기준으로
input.ports[i].network == input.networks[j].id # 그 포트의 네트워크를 찾아서
input.networks[j].public # 그 네트워크가 public 이면
}본 단락에서는 리눅스 기준으로 OPA 서버를 설치하고 사용하는 방법에 대해 다룬다. 앞 단락에서 만든 input-example.json과 policy-example.rego파일을 사용한다.
opa 바이너리를 다운받는다.
curl -L -o opa
chmod 755 opa
# sudo mv opa /usr/local/bin
'opa eval' 명령을 통해 cli로 룰들을 테스트 해볼수 있다.
내장함수의 호출
./opa eval "1*2+3"
데이터와 정책을 집어 넣어 진행내역을 확인
$ ./opa eval -i input-example.json -d policy-example.rego "data.example.violation[x]"
{
"result": [
{
"expressions": [
{
"value": "busybox",
"text": "data.example.violation[x]",
"location": {
"row": 1,
"col": 1
}
}
],
"bindings": {
"x": "busybox"
}
},
{
"expressions": [
{
"value": "ci",
"text": "data.example.violation[x]",
"location": {
"row": 1,
"col": 1
}
}
],
"bindings": {
"x": "ci"
}
}
]
}
스크립트에서 전체적인 결과로 성공과 실패받고 싶다면 --fail-defined 옵션과 이전결과 변수($?)를 활용하자.
./opa eval --fail-defined -i input-example.json -d policy-example.rego "data.example.violation[x]"
echo $?
대화형으로 테스트 해볼 수 있다.
시작시 데이터 로딩
$ ./opa run input-example.json
OPA 0.35.0 (commit a54537a, built at 2021-12-01T02:11:47Z)
Run 'help' to see a list of commands and check for updates.
> data.servers[0].protocols[1]
"ssh"
시작시 데이터와 정책 로딩
$ ./opa run policy-example.rego repl.input:input-example.json
OPA 0.35.0 (commit a54537a, built at 2021-12-01T02:11:47Z)
Run 'help' to see a list of commands and check for updates.
> data.example.public_server[s]
+-------------------------------------------------------------------+-------------------------------------------------------------------+
| s | data.example.public_server[s] |
+-------------------------------------------------------------------+-------------------------------------------------------------------+
| {"id":"app","ports":["p1","p2","p3"],"protocols":["https","ssh"]} | {"id":"app","ports":["p1","p2","p3"],"protocols":["https","ssh"]} |
| {"id":"ci","ports":["p1","p2"],"protocols":["http"]} | {"id":"ci","ports":["p1","p2"],"protocols":["http"]} |
+-------------------------------------------------------------------+-------------------------------------------------------------------+
--server 옵션을 사용하면 웹기반 opa서버가 생성되며 더 브라우저를 통해 좀더 유연한 테스트가 가능하다.
서버를 띄우면
$ ./opa run --server ./policy-example.rego
{"addrs":[":8181"],"diagnostic-addrs":[],"level":"info","msg":"Initializing server.","time":"2021-12-13T07:16:41Z"}
기본 포트는 8181이므로 이에 접근

Playground(https://play.openpolicyagent.org/)는 별도의 서버없이 브라우저만으로 사용해 볼수있는 웹앱서비스 이다. 위에서 살펴본 기능보다 확장된 UI를 제공하고 추가적으로 Example들을 제공하여 용도에따른 참고할 수 있다.


본 블로그에서는 클라우드 네이티브 환경에서 보안과 정책의 필요성에 대해 알아보고 대표적인 사용예로 쿠버네티스 환경에서 사실상 표준으로 떠오르고 있는 OPA를 소개했다. MSA가 보편화되고 관리해야할 지점들이 많아지면서 Policy as Code라는 주제는 더욱 중요해질 것으로 보인다.
https://heavenly-part-d73.notion.site/OPA-681e4ddcd73e493fab794389fae0a42c
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.