ORY Project - heshed/aPaaS GitHub Wiki

ORY

Open Source Identity Infrastructure and Services ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ, ๊ถŒํ•œ ๋ฐ ์—ญํ•  ๊ด€๋ฆฌ, OAuth 2.0 ๋ฐ OpenID

ORY ํ”„๋กœ์ ํŠธ

  • ORY Hydra
    • OAuth 2.0 ๋ฐ OpenID Connect ๊ณต๊ธ‰์ž์ž…๋‹ˆ๋‹ค.
  • ORY Oathkeeper
    • ์•„์ด๋”” ๋ฐ ์•ก์„ธ์Šค ํ”„๋ก์‹œ์ž…๋‹ˆ๋‹ค.
  • ORY Keto
    • ์•ก์„ธ์Šค ์ œ์–ด ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค.
  • ORY Kratos
    • ID ๊ด€๋ฆฌ ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค.

img

ํŠน์ง•

  • ๋ฐ์ดํ„ฐ์ €์žฅ
    • RDBMS(PostgreSQL, MySQL, SQLite)์— ์ €์žฅ
    • CockroachDB ๋ฒ ํƒ€
    • ๋ฉ”๋ชจ๋ฆฌ (dsn ์„ memory ๋กœ ์ง€์ •)

k8s install

helm repo add ory https://k8s.ory.sh/helm/charts
helm repo update

๊ฐœ๋ฐœ ์ง„ํ–‰์ค‘์ธ ๊ฒƒ์œผ๋กœ ๋ณด์ด๊ณ , hydra, oathkeeper ์ •๋„๋งŒ ๋“ค์–ด ์žˆ๋Š” ๋“ฏ ํ•จ. ๋ฌธ์„œ ๋ถ€์‹ค.

docker examples

docker https://github.com/ory/examples/tree/master/full-stack

git clone https://github.com/ory/examples.git ory-example
cd ory-example
make start-full-stack

5๋ถ„ ์ •๋„ ๋Œ€๊ธฐํ›„.. ๋กœ๊ทธ ํ™•์ธ

docker logs hydra-bc_postgresd_1
docker logs hydra-bc_keto-migrate_1
docker logs hydra-bc_oathkeeper-migrate_1
docker logs hydra-bc_hydra-migrate_1
docker logs hydra-bc_services_1

์„œ๋น„์Šค ํ™•์ธ

$ curl http://localhost:4445/clients
$ curl http://localhost:4456/rules
$ curl http://localhost:4466/engines/acp/ory/exact/policies
$ curl http://localhost:4466/engines/acp/ory/exact/roles

ORY Keto

Open Policy Agent ์—”์ง„์„ ์‚ฌ์šฉ

Keto Access Control Policies

  • https://www.ory.sh/docs/keto/engines/acp-ory
  • Access Control Policy DSL ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•จ.
  • Role Based Access Control(RBAC)๋Š” ๋ฏธ๊ตฌํ˜„๋œ ์ƒํƒœ(๊ฐœ๋ฐœ ๋ฆฌ์†Œ์Šค๊ฐ€ ์—†๋‹ค๊ณ )

ACL ๊ตฌ์„ฑ

  • subjects : "identity, user"

  • resources : ["member", "service", "collection" ]

  • actions : ["delete", "create", "read", "modify"]

    • ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ ํŒจํ„ด(์ž„์˜์˜ ๊ฐ’ ์…‹ํŒ… ๊ฐ€๋Šฅ)
  • effect : "allow/deny"

    • ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ ‘๊ทผ์ œ์–ด ํ—ˆ์šฉ์—ฌ๋ถ€ (์ž„์˜์˜ ๊ฐ’ ์…‹ํŒ… ๊ฐ€๋Šฅ)
  • ory policies

[{
  "subjects": ["role:owner"],
  "resources": [
    "resources:member",
    "resources:service",
    "resources:collection"
  ],
  "actions": ["delete", "create", "read", "modify"],
  "effect": "allow"
},
{
  "subjects": ["role:admin"],
  "resources": [
    "resources:service",
    "resources:collection"
  ],
  "actions": ["delete", "create", "read", "modify"],
  "effect": "allow"
},
{
  "subjects": ["role:admin"],
  "resources": [
    "resources:member"
  ],
  "actions": ["read"],
  "effect": "allow"
},
{
  "subjects": ["role:user"],
  "resources": [
    "resources:member",
    "resources:service",
    "resources:collection"
  ],
  "actions": ["read"],
  "effect": "allow"
}
]

RBAC ์™€ ์ •ํ™•ํžˆ ๋งค์นญ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— RBAC ๋ฃฐ๊ณผ ๋น„์Šทํ•œ ํšจ๊ณผ๋ฅผ ๋‚ด๋ ค๋ฉด https://www.ory.sh/docs/keto/sdk/api#get-an-ory-access-control-policy-role roles ์— role-member ๋ฐ์ดํ„ฐ๋กœ ๊ทธ๋ฃนํ™”ํ•œ role ์„ ์ƒ์„ฑํ•˜๊ณ , policy api ์— subjects์— role ๊ทธ๋ฃน์„ ์ง€์ •ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•˜๋ฉด ๋˜๊ฒ ๋‹ค.

member ๋ฐ์ดํ„ฐ

  • ํ‚ค member:kakao.com:heshed
[
  {"id": "role:owner", "members": ["member:kakao.com:heshed", "member:kakao.com:heshed2"]},
  {"id": "role:admin", "members": ["member:kakao.com:heshed", "member:kakao.com:heshed2"]}
  {"id": "role:user", "members": ["member:kakao.com:heshed", "member:kakao.com:heshed2"]}
]

ํŒจํ„ด ๋งค์นญ

keto๋Š” string ๋งค์นญ, glob ํŒจํ„ด๋งค์นญ URNs, ์ •๊ทœํ‘œํ˜„์‹, ์กฐ๊ฑด๋ฌธ๋“ค, CIDR ์กฐ๊ฑด, Subject ์กฐ๊ฑด ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์ž์„ธํ•œ ์‚ฌํ•ญ์€ https://www.ory.sh/docs/keto/engines/acp-ory ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

{
  "subjects": ["users:*"],
  "actions": ["get", "create"],
  "resources": ["resources:articles:*", "resources:{accounts,profiles}:*"],
  "effect": "allow"
}

Best Practices

  • scope ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด URN ๋„ค์ด๋ฐ์„ ์ž‘์„ฑํ•˜๋„๋ก ํ•œ๋‹ค.
Do not: my-resource
Do: myorg.com:my-resource

Do not: myorg.com:<subject-id>, myorg.com:<resource-id>, myorg.com:<action-id>
Do: myorg.com:subjects:<subject-id>, myorg.com:resources:<resource-id>, myorg.com:actions:<action-id>
Do: subjects:myorg.com:<subject-id>, resources:myorg.com:<resource-id>, actions:myorg.com:<action-id>
  • Multi-Tenant Systems
Do: resources:myorg.com:tenants:<tenant-id>:<resource-id>

์ผ๋ถ€ ํ™˜๊ฒฝ์—๋Š” ํ•ด๋‹น ์กฐ์ง์— ์†ํ•œ ์„œ๋ธŒ์กฐ์ง ๋ฐ ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์—์„œ ๋‹ค์Œ URN semantics๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Do: resources:myorg.com:organizations:<organization-id>:projects:<project-id>:<resource-id>

ORY OathKeeper

  • incoming HTTP ๋ฆฌํ€˜์ŠคํŠธ์— ๋Œ€ํ•ด์„œ ๊ถŒํ•œ ์ฒดํฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • ํด๋ผ์šฐ๋“œ ์•„ํ‚คํ…์ฒ˜์—์„œ ์ •์ฑ…์ˆ˜ํ–‰์ง€์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. reverse proxy๋กœ ๋‹จ๋…์œผ๋กœ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ API Gateway ์ œํ’ˆ๊ณผ ํ”Œ๋Ÿฌ๊ทธ์ธ์ฒ˜๋Ÿผ ๊ฒฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. (Kong, Nginx, Envoy, AWS API Gateway,...)

  • ๊ตฌํ˜„ํ•œ ๋ฌธ์ œ ๋„๋ฉ”์ธ๊ณผ ์Šค์ฝ”ํ”„๋Š” Zero-Trust Network Architecture, Identity And Access Proxy (IAP)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. (https://www.beyondcorp.com/)

  • ORY Oathkeeper ๋Š” ORY Hydra, ORY Keto ์™€ ๋‹จ๋…์œผ๋กœ ๋™์ž‘์„ ์ž˜ํ•˜๋ฉฐ, Oathkeeper's Access Control Decision API ๋Š” ๋‹ค๋ฅธ ์ œํ’ˆ๋“ค๊ณผ๋„ ์ž˜ ๊ฒฐํ•ฉํ•˜์—ฌ ๋™์ž‘ํ•œ๋‹ค.

    • Ambassador via auth service
    • Envoy via the External Authorization HTTP Filter
    • AWS API Gateway via Custom Authorizers
    • Nginx via Authentication Based on Subrequest Result

๋™์ž‘ ๋ชจ๋“œ

Reverse Proxy

img

Example

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฆฌํ€˜์ŠคํŠธ๊ฐ€ ๋“ค์–ด์˜จ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„๋•Œ

GET /my-service/whatever HTTP/1.1
Host: oathkeeper-proxy:4455
Authorization: bearer some-token

์•„๋ž˜์˜ rule ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด

{
  "id": "some-id",
  "upstream": {
    "url": "http://my-backend-service"
  },
  "match": {
    "url": "http://oathkeeper-proxy:4455/my-service/whatever",
    "methods": ["GET"]
  },
  "authenticators": [
    {
      "handler": "anonymous"
    }
  ],
  "authorizer": {
    "handler": "allow"
  },
  "mutators": [
    {
      "handler": "noop"
    }
  ]
}

ORY Oauthkeeper ๋Š” ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ forward ํ•  ๊ฒƒ์ด๋‹ค.

GET /my-service/whatever HTTP/1.1
Host: my-backend-service:4455
Authorization: bearer some-token

Access Control Decision API

๋ฆฌํ€˜์ŠคํŠธ๋ฅผ verify ํ•˜๊ธฐ ์œ„ํ•ด decisoins endpoint api ๋ฅผ ๋ณด๋‚ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • GET /decisions/v1/api
  • PUT /decisions/my/other/api
  • DELETE /decisions/users?foo=?bar

img

Example

Assuming you are making the following request to ORY Oathkeeper's Access Control Decision API

GET /decision/my-service/whatever HTTP/1.1
Host: oathkeeper-api:4456
Authorization: bearer some-token

and you have the following rule defined (which allows this request)

{
  "id": "some-id",
  "match": {
    "url": "http://oathkeeper-api:4456/my-service/whatever",
    "methods": ["GET"]
  },
  "authenticators": [
    {
      "handler": "noop"
    }
  ],
  "authorizer": {
    "handler": "allow"
  },
  "mutators": [
    {
      "handler": "noop"
    }
  ]
}

then this endpoint will directly respond with HTTP Status Code 200:

HTTP/1.1 200 OK
Authorization: bearer some-token

If any other status code is returned, the request must not be allowed, for example:

HTTP/1.1 401 OK
Content-Length: 0
Connection: Closed

It is also possible to have this endpoint return other error responses such as the HTTP Status Found (HTTP Status Code 302), depending configured on the error handling. Use this feature only if your Reverse Proxy supports these type of responses.

Depending on the mutator defined by the access rule, the HTTP Response might contain additional or mutated HTTP Headers:

HTTP/1.1 200 OK
X-User-ID: john.doe

Decision Engine

  1. Access Rule Matching
  2. Authentication
  3. Authorization
  4. Mutation
  • Acess Rule ์€ ์„ธ์…˜๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํฌ์›Œ๋”ฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • X-User-ID: the-user-id -> Authorization: Bearer the.jwt.token img
โš ๏ธ **GitHub.com Fallback** โš ๏ธ