기존에 Cognito를 이용해서 Kibana의 접근을 제한해왔었다.

기존에는 단순히 kibana 접근만 제한하고 있어서 audit 통과가 목적이었지만

운영하다보니 Role을 부여해서 세세하게 접근을 제한하고 싶어졌다.

Elasticsearch의 index단위로 접근을 제한하고 read/write 권한 조절하기 위하여

Opendistro를 이용하기로 했다.

 

Elasticsearch 설치형에서는 이미 사용중이었고

AWS의 ElasticSearch에 지원을 한지 좀 되었지만.. 이제 반영하려한다.

 

Launching Open Distro for Elasticsearch security features on Amazon Elasticsearch Service | Amazon Web Services

We are excited to announce that we are making new Open Distro for Elasticsearch security features available on Amazon Elasticsearch Service. Amazon Elasticsearch Service is frequently used for sensitive enterprise workloads, and today’s launch adds multi

aws.amazon.com

 

Open Distro의 API가 있겠거니하고 문서를 찾아본다.

 

API

Documentation for Open Distro for Elasticsearch, the community-driven, 100% open source distribution of Elasticsearch with advanced security, alerting, deep performance analysis, and more.

opendistro.github.io


Account Create 요청이다.

#### REQUEST

PUT _opendistro/_security/api/internalusers/<username>
{
  "password": "kirkpass",
  "backend_roles": ["captains", "starfleet"],
  "attributes": {
    "attribute1": "value1",
    "attribute2": "value2"
  }
}

 

backend role 대신에 일반 role을 맵팽하는 방식을 사용할 것이고,

attributes 정보는 아직은 안쓸것이라서 

password만 사용할 예정이다. (이것도 default pw로 처음 로그인할때 알아서 바꾸게 해줄 방법은 없으려나..)

 

1차로 구현했던 코드

아래의 내용은 본인 환경에 맞게 전부 수정해서 사용해야 한다.

 

참고로 opendistro_admin, opendistro_admin_pw는 실제 admin 계정의 것을 사용하거나, 계정관련 security menu 접근 권한이 있는 계정의 정보를 이용한다.

import json
import requests

def opendistro_create_user():
    user_name = 'testuser'
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/internalusers/%s' % (user_name)
    url = base_url + path
    payload = {'password': 'INITpassword1234!@#$', 'backend_roles': ['read_write_all_index']}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), data=payload)
    print(rs.content)

매뉴얼에 나와있는대로 PUT을 수행했다.

결과는 에러

b'{"error":"Content-Type header is missing","status":406}'

해더를 빼먹었으니 넣어준다.

 

2차로 구현한 코드

import json
import requests

def opendistro_create_user():
    user_name = 'testuser'
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/internalusers/%s' % (user_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'password': 'INITpassword1234!@#$', 'backend_roles': ['read_write_all_index']}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), data=payload, headers=headers)
    print(rs.content)

결과는 다시 에러

b'{"status":"error","reason":"Could not parse content of request."}'

data type이 문제로 보인다.

 

requests.put 할때 파라메터를 수정해주는데, 해결방안이 2개가 있다. 

  1. data=json.dumps(payload)
  2. json=payload

2안을 택했다.

3차로 구현한 코드 [성공]

import json
import requests

def opendistro_create_user():
    user_name = 'testuser'
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/internalusers/%s' % (user_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'password': 'INITpassword1234!@#$', 'backend_roles': ['read_write_all_index']}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), json=payload, headers=headers)
    print(rs.content)

결과는 성공이다.

b'{"status":"CREATED","message":"\'testuser\' created."}'

 

Role Mapping 관련해서는 

mapping 해주거나 backend_role을 사용하도록 해야한다.

다른 동료들이 나중에 Kibana에서 보고 처리하기 쉬울것 같아서 mapping 해주는 방식을 선택하였다.

#### REQUEST

PUT _opendistro/_security/api/rolesmapping/<role>
{
  "backend_roles" : [ "starfleet", "captains", "defectors", "cn=ldaprole,ou=groups,dc=example,dc=com" ],
  "hosts" : [ "*.starfleetintranet.com" ],
  "users" : [ "worf" ]
}

여기에서 나는 role만 매핑할거라서 사용하게될 정보는 users만 사용한다.

그리고 미리 role을 kibana에서 생성해두고 그것을 사용한다.

 

1차 시도한 코드

import json
import requests

   
def opendistro_mapping_role(user_name, role_name='read_write_limit'):
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/rolesmapping/%s' % (role_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'users': [user_name]}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), headers=headers, json=payload)
    print(rs.content)

돌려보니 되는줄 알았다.

문제는 users라고 되어있는것을 제대로 파악 못한것이 문제.

이런식으로 루프 돌려가면서 호출했더니 가장 마지막에 호출한 user 정보 1개만 남았다.

for user in user_list:

    opendistro_mapping_role(user)

 

 2차 시도한 코드는 원하는대로 동작 [성공]

import json
import requests

   
def opendistro_mapping_role(user_list, role_name='read_write_limit'):
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/rolesmapping/%s' % (role_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'users': user_list}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), headers=headers, json=payload)
    print(rs.content)

1차에서 개별 사용자를 처리하려고 loop 돌렸던 것을 없애고 

그 사용자 list를 인자값으로 넘겼더니 제대로 mapping 된것을 kibana에서 확인하였다.

사용자 list라함은 이런 형태로 값이 저장되어있다.

  • user_list = ['user1', 'user2', 'user3', ... , ... , 'user100']

 

 

반응형

'Infra' 카테고리의 다른 글

Dockerfile Best Practice (모범 사례)  (1) 2022.11.03
인프라 개념 LACP  (0) 2022.06.10
Cloudfront와 S3를 이용한 웹 서비스 구성  (0) 2021.03.10
Hashicorp Terraform (테라폼)  (0) 2020.10.28
AWS Subnet 생성하기  (0) 2020.07.23

+ Recent posts