"Keystone 아키텍처"의 두 판 사이의 차이

 
4번째 줄: 4번째 줄:
;키스톤 아키텍처
;키스톤 아키텍처
https://docs.openstack.org/keystone/2024.1/getting-started/architecture.html
https://docs.openstack.org/keystone/2024.1/getting-started/architecture.html
 
----
대부분의 설계에서는 대부분의 배포에서 인증 백엔드가 기존 사용자 시스템 앞에 있는 [[심(shim)]]이라고 가정합니다.
대부분의 설계에서는 대부분의 배포에서 인증 백엔드가 기존 사용자 시스템 앞에 있는 [[심(shim)]]이라고 가정합니다.



2024년 7월 5일 (금) 21:09 기준 최신판

1 개요[ | ]

Keystone Architecture
키스톤 아키텍처

https://docs.openstack.org/keystone/2024.1/getting-started/architecture.html


대부분의 설계에서는 대부분의 배포에서 인증 백엔드가 기존 사용자 시스템 앞에 있는 심(shim)이라고 가정합니다.

2 서비스[ | ]

Keystone은 하나 이상의 엔드포인트에 노출된 내부 서비스 그룹으로 구성됩니다. 이러한 서비스 중 다수는 프론트엔드에서 결합된 방식으로 사용됩니다. 예를 들어, 인증 호출은 Identity 서비스로 사용자/프로젝트 자격증명을 검증하고 성공 시 Token 서비스를 통해 토큰을 생성하고 반환합니다.

2.1 아이덴티티[ | ]

Identity 서비스는 인증 자격증명 검증 및 사용자와 그룹에 대한 데이터를 제공합니다. 기본적인 경우에는, 이 데이터가 Identity 서비스에 의해 관리되어, 이 데이터와 관련된 모든 CRUD 작업도 처리할 수 있습니다. 더 복잡한 경우에는, 대신 귄위 백엔드 서비스에서 데이터를 관리합니다. 예를 들어, Identity 서비스가 LDAP의 프론트엔드 역할을 할 때 LDAP 서버가 진실의 원천(source of truth)이며, Identity 서비스의 역할은 그 정보를 정확하게 전달하는 것입니다.

2.1.1 사용자[ | ]

사용자(Users)는 개인 API 소비자를 나타냅니다. 사용자는 특정 도메인에 속해야 하며, 따라서 모든 사용자 이름은 전역적으로 고유하지 않고 해당 도메인 내에서만 고유합니다.

2.1.2 그룹[ | ]

그룹(Groups)은 사용자 모음을 나타내는 묶음(container)입니다. 그룹 역시 특정 도메인에 속해야 하며, 따라서 모든 그룹 이름은 전역적으로 고유하지 않고 해당 도메인 내에서만 고유합니다.

2.2 리소스[ | ]

Resource 서비스는 프로젝트 및 도메인에 대한 데이터를 제공합니다.

2.2.1 프로젝트[ | ]

프로젝트(Projects)는 OpenStack에서 소유권의 기본 단위를 나타내며, OpenStack의 모든 자원은 특정 프로젝트에 의해 소유되어야 합니다. 프로젝트 자체는 특정 도메인에 소속되어야 하며, 따라서 모든 프로젝트 이름은 전역적으로 고유하지 않고 해당 도메인 내에서 고유합니다. 프로젝트의 도메인이 지정되지 않은 경우 기본 도메인에 추가됩니다.

2.2.2 도메인[ | ]

도메인(Domains)은 프로젝트, 사용자, 그룹을 위한 상위 묶음(container)입니다. 각 도메인은 정확히 하나의 도메인에 소속됩니다. 각 도메인은 API에서 보이는 이름 속성이 존재하는 네임스페이스를 정의합니다. Keystone은 'Default'라는 이름의 기본 도메인을 제공합니다.

Identity v3 API에서 속성의 고유성은 다음과 같습니다:

  • 도메인 이름: 모든 도메인에서 전역적으로 고유합니다.
  • 역할 이름: 소유 도메인 내에서 고유합니다.
  • 사용자 이름: 소유 도메인 내에서 고유합니다.
  • 프로젝트 이름: 소유 도메인 내에서 고유합니다.
  • 그룹 이름: 소유 도메인 내에서 고유합니다.

묶음(container) 아키텍처에 따라, 도메인은 OpenStack 리소스의 관리 권한을 위임하는 방법으로 사용될 수 있습니다. 도메인의 사용자는 적절한 할당이 부여된 경우 다른 도메인의 리소스에 접근할 수 있습니다.

2.3 할당[ | ]

Assignment 서비스는 역할과 역할 할당에 대한 데이터를 제공합니다.

2.3.1 역할[ | ]

역할(Roles)은 최종 사용자가 얻을 수 있는 권한 수준을 결정합니다. 역할은 도메인 수준 또는 프로젝트 수준에서 부여될 수 있습니다. 역할은 개별 사용자 또는 그룹 수준에서 할당될 수 있습니다. 역할 이름은 소유 도메인 내에서 고유합니다.

2.3.2 역할 할당[ | ]

역할(Role), 리소스(Resource), 아이덴티티(Identity)을 포함하는 3-튜플입니다.

2.4 토큰[ | ]

Token 서비스는 사용자의 자격증명이 이미 확인된 후 요청을 인증하는 데 사용되는 토큰을 검증하고 관리합니다.

2.5 카탈로그[ | ]

Catalog 서비스는 엔드포인트 탐색에 사용되는 엔드포인트 레지스트리를 제공합니다.

3 애플리케이션 구축[ | ]

Keystone는 여러 서비스에 대한 HTTP 프론트엔드입니다. Rocky 릴리스 이후로 Keystone은 Flask-RESTful 라이브러리를 사용하여 이러한 서비스에 REST API 인터페이스를 제공합니다.

Keystone은 keystone.server.flask.common에서 Flask-RESTful과 관련된 기능을 정의합니다. Keystone은 클래스 keystone.server.flask.common.ResourceBase를 상속하는 API 리소스를 생성하고 각 지원 HTTP 메소드인 GET, PUT, POST, PATCH, DELETE에 대한 메소드를 노출합니다. 예를 들어, User 리소스는 다음과 같이 생깁니다:

class UserResource(ks_flask.ResourceBase):
    collection_key = 'users'
    member_key = 'user'
    get_member_from_driver = PROVIDERS.deferred_provider_lookup(
        api='identity_api', method='get_user')

    def get(self, user_id=None):
        """Get a user resource or list users.
        GET/HEAD /v3/users
        GET/HEAD /v3/users/{user_id}
        """
        ...

    def post(self):
        """Create a user.
        POST /v3/users
        """
        ...

class UserChangePasswordResource(ks_flask.ResourceBase):
    @ks_flask.unenforced_api
     def post(self, user_id):
         ...

각 API 리소스의 라우트는 keystone.server.flask.common.APIBase를 상속하는 클래스에 의해 정의됩니다. 예를 들어, UserAPI는 다음과 같이 생깁니다:

class UserAPI(ks_flask.APIBase):
    _name = 'users'
    _import_name = __name__
    resources = [UserResource]
    resource_mapping = [
        ks_flask.construct_resource_map(
            resource=UserChangePasswordResource,
            url='/users/<string:user_id>/password',
            resource_kwargs={},
            rel='user_change_password',
            path_vars={'user_id': json_home.Parameters.USER_ID}
        ),
     ...

keystone.server.flask.common.APIBase_add_resources() 또는 _add_mapped_resources() 메소드는 리소스와 API를 바인딩합니다. 각 API 내에서는 하나 이상의 관리자가 로드되며(예: keystone.catalog.core.Manager 참조), 이는 Keystone 구성에 따라 적절한 서비스 드라이버를 로드하는 얇은 래퍼 클래스입니다.

  • Assignment
    • keystone.api.role_assignments
    • keystone.api.role_inferences
    • keystone.api.roles
    • keystone.api.os_inherit
    • keystone.api.system
  • Authentication
    • keystone.api.auth
    • keystone.api.ec2tokens
    • keystone.api.s3tokens
  • Catalog
    • keystone.api.endpoints
    • keystone.api.os_ep_filter
    • keystone.api.regions
    • keystone.api.services
  • Credentials
    • keystone.api.credentials
  • Federation
    • keystone.api.os_federation
  • Identity
    • keystone.api.groups
    • keystone.api.users
  • Limits
    • keystone.api.registered_limits
    • keystone.api.limits
  • Oauth1
    • keystone.api.os_oauth1
  • Policy
    • keystone.api.policy
  • Resource
    • keystone.api.domains
    • keystone.api.projects
  • Revoke
    • keystone.api.os_revoke
  • Trust
    • keystone.api.trusts

4 서비스 백엔드[ | ]

각 서비스는 다양한 환경과 요구에 맞게 Keystone을 구성할 수 있도록 백엔드를 사용하도록 설정할 수 있습니다. 각 서비스의 백엔드는 keystone.conf 파일에서 해당 서비스와 관련된 그룹 아래에 있는 driver 키로 정의됩니다.

일반 클래스는 각 백엔드 아래에 존재하여 모든 구현에 대한 추상 기본 클래스를 제공하고 예상되는 서비스 구현을 식별합니다. 추상 기본 클래스는 서비스의 backends 디렉토리에 base.py라는 이름으로 저장됩니다. 서비스에 대한 해당 드라이버는 다음과 같습니다:

  • keystone.assignment.backends.base.AssignmentDriverBase
  • keystone.assignment.role_backends.base.RoleDriverBase
  • keystone.auth.plugins.base.AuthMethodHandler
  • keystone.catalog.backends.base.CatalogDriverBase
  • keystone.credential.backends.base.CredentialDriverBase
  • keystone.endpoint_policy.backends.base.EndpointPolicyDriverBase
  • keystone.federation.backends.base.FederationDriverBase
  • keystone.identity.backends.base.IdentityDriverBase
  • keystone.identity.mapping_backends.base.MappingDriverBase
  • keystone.identity.shadow_backends.base.ShadowUsersDriverBase
  • keystone.oauth1.backends.base.Oauth1DriverBase
  • keystone.policy.backends.base.PolicyDriverBase
  • keystone.resource.backends.base.ResourceDriverBase
  • keystone.resource.config_backends.base.DomainConfigDriverBase
  • keystone.revoke.backends.base.RevokeDriverBase
  • keystone.token.providers.base.Provider
  • keystone.trust.backends.base.TrustDriverBase

Keystone 서비스 중 하나에 대한 백엔드 드라이버를 구현하는 경우, 이 클래스들을 서브클래스로 사용해야 합니다.

4.1 템플릿 백엔드[ | ]

Keystone 프로젝트의 서비스 카탈로그와 관련된 일반적인 사용사례를 위해 설계된 템플릿 백엔드는 사전설정된 템플릿을 확장하여 카탈로그 데이터를 제공하는 카탈로그 백엔드입니다.

예시 paste.deploy 설정 (ConfigParser의 인터폴레이션을 피하기 위해 % 대신 $를 사용)

[DEFAULT]
catalog.RegionOne.identity.publicURL = http://localhost:$(public_port)s/v3
catalog.RegionOne.identity.adminURL = http://localhost:$(public_port)s/v3
catalog.RegionOne.identity.internalURL = http://localhost:$(public_port)s/v3
catalog.RegionOne.identity.name = 'Identity Service'

5 데이터 모델[ | ]

Keystone은 다양한 스타일의 백엔드에 적합하도록 처음부터 설계되었습니다. 따라서 많은 메소드와 데이터 유형은 자신이 처리할 수 있는 것보다 더 많은 데이터를 받아들이고 이를 백엔드로 전달할 수 있습니다.

주요 데이터 유형은 다음과 같습니다:

  • 사용자(User): 계정 자격증명을 가지고 있으며, 하나 이상의 프로젝트 또는 도메인과 연결됩니다.
  • 그룹(Group): 사용자의 모음으로, 하나 이상의 프로젝트 또는 도메인과 연결됩니다.
  • 프로젝트(Project): OpenStack의 소유 단위로, 하나 이상의 사용자를 포함합니다.
  • 도메인(Domain): OpenStack의 소유 단위로, 사용자, 그룹 및 프로젝트를 포함합니다.
  • 역할(Role): 많은 사용자-프로젝트 쌍과 연관된 일급 메타데이터입니다.
  • 토큰(Token): 사용자 또는 사용자와 프로젝트와 연관된 식별 자격증명입니다.
  • 추가 정보(Extras): 사용자-프로젝트 쌍과 연관된 키-값 메타데이터의 버킷입니다.
  • 규칙(Rule): 작업을 수행하기 위한 일련의 요구 사항을 설명합니다.

일반적인 데이터 모델은 사용자와 그룹, 프로젝트와 도메인 간의 다대다 관계를 허용하지만, 실제 백엔드 구현은 해당 기능을 다양한 수준으로 활용합니다.

6 CRUD에 대한 접근방식[ | ]

큰 회사에서 실제로 배포되는 시스템은 기존의 사용자 시스템에서 사용자와 그룹을 관리할 것으로 예상되지만, 개발 및 테스트를 위해 다양한 CRUD 작업이 제공됩니다.

CRUD는 백엔드가 이를 지원할 필요가 없는 핵심 기능 세트의 확장 또는 추가 기능으로 취급됩니다. CRUD 작업을 지원하지 않는 서비스의 백엔드는 keystone.exception.NotImplemented 예외를 발생시킬 것으로 예상됩니다.

7 인가에 대한 접근방식 (정책)[ | ]

시스템의 다양한 컴포넌트는 사용자가 해당 액션을 수행할 권한이 있는지 여부에 따라 다른 액션을 허용해야 합니다.

Keystone의 목적을 위해 다음과 같은 몇 가지 인가 수준만을 확인합니다:

  • 액션을 수행하는 사용자가 관리자(admin)로 간주되는지 요구합니다.
  • 액션을 수행하는 사용자가 참조된 사용자와 매치하는지 요구합니다.

정책 엔진을 사용하려는 다른 시스템은 추가적인 스타일의 확인이 필요하며, 완전히 맞춤형 백엔드를 작성할 수 있습니다. 기본적으로, Keystone은 oslo.policy에서 유지관리되는 정책 집행을 활용합니다.

7.1 규칙[ | ]

확인할 매치 목록이 주어지면, 자격증명이 매치 항목을 포함하는지 여부를 단순히 확인합니다. 예를 들면 다음과 같습니다:

credentials = {'user_id': 'foo', 'is_admin': 1, 'roles': ['nova:netadmin']}

# 관리자 전용 호출:
policy_api.enforce(('is_admin:1',), credentials)

# 관리자 또는 소유자 호출:
policy_api.enforce(('is_admin:1', 'user_id:foo'), credentials)

# 넷관리자(netadmin) 호출:
policy_api.enforce(('roles:nova:netadmin',), credentials)

자격증명은 일반적으로 Identity API의 ‘extras’ 부분에서 사용자 메타데이터를 통해 생성됩니다. 따라서 사용자의 ‘role’을 추가하는 것은 사용자 메타데이터에 역할을 추가하는 것과 같습니다.

7.2 기능 RBAC[ | ]

(아직 구현되지 않았습니다.)

인가에 대한 또 다른 접근방식은 역할을 특정 작업에 대한 권한과 매핑하는 액션 기반 접근 방식입니다. 예를 들면 다음과 같습니다:

credentials = {'user_id': 'foo', 'is_admin': 1, 'roles': ['nova:netadmin']}

# 정책 추가
policy_api.add_policy('action:nova:add_network', ('roles:nova:netadmin',))

policy_api.enforce(('action:nova:add_network',), credentials)

백엔드에서는 ‘action:nova:add_network'’에 대한 정책을 조회한 다음, 자격증명에 대해 ‘간단한 매칭’ 스타일의 매칭을 수행합니다.

8 인증에 대한 접근방식[ | ]

Keystone은 여러 인증 플러그인을 제공하며, 이들은 모두 keystone.auth.plugins.base를 상속받습니다. 다음은 사용 가능한 플러그인 목록입니다.

가장 기본적인 플러그인인 password를 예로 들면, Keystone과 인증하기 위해 두 가지 정보가 필요합니다. 하나는 Resource 정보이고, 다른 하나는 Identity 정보입니다.

다음은 POST 데이터를 이용한 예제 호출입니다:

{
    "auth": {
        "identity": {
            "methods": [
                "password"
            ],
            "password": {
                "user": {
                    "id": "0ca8f6",
                    "password": "secretsecret"
                }
            }
        },
        "scope": {
            "project": {
                "id": "263fd9"
            }
        }
    }
}

여기서 사용자(ID: 0ca8f6)가 프로젝트(ID: 263fd9)에 스코프된 토큰을 가져오려고 합니다.

이제, 이름을 사용하여 동일한 호출을 수행하려면 도메인에 대한 정보를 제공해야 합니다. 이는 사용자 이름이 주어진 도메인 내에서만 고유하며, 사용자 ID는 배포 전체에서 고유하기 때문입니다. 따라서 인증 요청은 다음과 같습니다:

{
    "auth": {
        "identity": {
            "methods": [
                "password"
            ],
            "password": {
                "user": {
                    "domain": {
                        "name": "acme"
                    },
                    "name": "userA",
                    "password": "secretsecret"
                }
            }
        },
        "scope": {
            "project": {
                "domain": {
                    "id": "1789d1"
                },
                "name": "project-x"
            }
        }
    }
}

사용자와 프로젝트 부분 모두 올바른 사용자와 프로젝트를 확인하기 위해 도메인 ID나 도메인 이름을 제공해야 합니다.

또한, 이를 명령줄 환경변수로 나타내려면 다음과 같이 할 수 있습니다:

$ export OS_PROJECT_DOMAIN_ID=1789d1
$ export OS_USER_DOMAIN_NAME=acme
$ export OS_USERNAME=userA
$ export OS_PASSWORD=secretsecret
$ export OS_PROJECT_NAME=project-x

사용자가 접근하려고 하는 프로젝트는 사용자가 속한 도메인 내에 있어야 한다는 점에 유의하세요.

8.1 스코프란 무엇인가?[ | ]

스코프(scope)는 여러가지 의미를 담은 용어입니다.

인증과 관련하여, 스코프는 사용자가 액세스하려는 리소스(프로젝트, 도메인 또는 시스템)를 지정하는 POST 데이터의 일부를 의미합니다.

토큰과 관련하여, 스코프는 토큰의 유효성을 나타냅니다. 예를 들어, 프로젝트 스코프 토큰은 처음 부여된 프로젝트에서만 유용합니다. 도메인 스코프 토큰은 도메인 관련 기능을 수행하는 데 사용할 수 있습니다. 시스템 스코프 토큰은 전체 배포에 영향을 미치는 API와 상호작용하는 데만 유용합니다.

사용자, 그룹, 프로젝트와 관련하여, 스코프는 종종 엔터티가 소속된 도메인을 의미합니다. 예를 들어, 도메인 X의 사용자는 도메인 X에 속한 사용자로 스코프됩니다.

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}