概要
pythonで、kerberos認証でhdfsに接続する方法についてです。
pythonのhdfsパッケージを利用してリクエストする方法と、
hdfsパッケージを使わずにrequestsパッケージでWebHDFS REST APIを叩く方法の2つを書きます。
以下の2つの環境で動作確認済です。
- Python 2.7.5
- Python 3.6.5
ケルベロス認証とは
手順に入る前に、ケルベロス認証について、以下のサイトがとても参考になるので貼っておきます。
http://www.infraexpert.com/study/security18.html
表をそのまま拝借しますが、以下の用語は覚えておいたほうがよいです。
ケルベロスの用語 | 説明 |
---|---|
KDC(Key Distribution Center) | サーバとユーザに関する信頼関係の情報を一括管理する中央データベース |
AS(Authentication Server) | 認証サーバ。ユーザからの認証を受け付けるサーバ |
TGS(Ticket Granting Server) | チケット発行サーバ。各サーバを利用するためのチケットを発行するサーバ |
プリンシパル(principal) | KDCが認証を行うユーザやサーバのこと |
レルム(realm) | 同じKDCの配下にあるシステムをグループとして定義する論理ネットワーク |
事前準備(共通)
こちらは、どちらの方法でも必要になります。
以下のファイルが必要になります。
- kerberos認証を利用するためのkeytabファイル
- SSLのCA証明書が必要な場合はCA証明書(必要な場合のみ)
krb5のインストール
kerberosのインストールをします。
$ sudo yum install -y krb5-workstation
$ sudo yum install -y krb5-devel
$ sudo yum install -y krb5-libs
設定ファイル
/etc/krb5/krb5.confの設定を行います。
[logging]
# kdcのログ
kdc = FILE:/var/log/krb5kdc.log
# admin_serverのログ
admin_server = FILE:/var/log/kadmind.log
# その他のログ
default = FILE:/var/log/krb5libs.log
# Kerberos 認証のデフォルト値を設定します。default_realm を設定する必要があります。
[libdefaults]
default_realm = MYDOMAIN.COM
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
# 各 Kerberos レルムの KDC を設定します。1 つのレルムに複数の kdc を設定できます。
# デフォルトのポート 88 を使用する場合はポートの指定を省略できます。
# ドメイン名を大文字にしたものをレルム名にするのが慣例です。
[realms]
MYDOMAIN.COM = {
kdc = mykdc.mydomain.com
# administrative server。通常はKerberosのマスターサーバー
admin_server = mykdc.mydomain.com
# プリンシパルとlocal user nameのマッピングルールを作れる
auth_to_local = RULE:[1:$1@$0](.*@MYDOMAIN.COM)s/@.*//
}
# 複数ある場合は更に記述
EXAMPLE.COM = {
kdc = kerberos.example.com
admin_server = kerberos.example.com
}
# ドメインやホストをrealmと結びつける設定。
# Active Directory ドメインを Kerberos レルムにマップします。
[domain_realm]
.example.com = MYDOMAIN.COM
example.com = MYDOMAIN.COM
各項目の説明をだいたい書いてありますが、詳しくは以下のサイトを参考にしてください。
-
参考
-
各設定値の参考
kinit(kerobers認証をする)
以下のコマンドを叩くと、kdc.conf ファイルに指定されている最長有効期限値 (max_life)の時間、kerberos認証されている状態が続きます。
定期的に実行するために、cronなどに設定しておくと便利です。
$ kinit -kt /secrets/keytab username
SSL CA証明書のパスを通す(必要な場合のみ)
接続にCA証明書が必要な場合は、以下の環境変数名でパスを設定しておく必要があります。
$ export REQUESTS_CA_BUNDLE=/etc/pki/tls/certs/ca-bundle.crt
これで事前準備は完了です。
hdfs + requests_kerberosを使う方法
hdfsパッケージのインストール
参考: http://hdfscli.readthedocs.io/en/latest/
hdfsパッケージ
$ pip install hdfs
kerberos認証に必要
$ pip install requests_kerberos
依存パッケージ
$ pip install requests
~/.hdfscli.cfgの設置
環境ごとに認証方式を変更したりできます。
以下の例では、prodではkerberos認証を使い、devでは使わない設定にしてあります。
参考: http://hdfscli.readthedocs.io/en/latest/api.html#module-hdfs.ext.kerberos
# 全体的な設定
[global]
# defaultのalias
default.alias = dev
# kerberos moduleをautoloadする
autoload.modules = hdfs.ext.kerberos
# devの設定
[dev.alias]
# devのhdfsのurl
url = https://dev.namenode:port
# prodの設定
[prod.alias]
# prodのhdfsのurl
url = https://prod.namenode:port
# kerberos認証をする
client = KerberosClient
# pathを指定するときのTOP階層の定義
# この場合はhttps://prod.namenode:port/webhdfs/v1/がトップになる
root = /
サンプルコード
ディレクトリの中身を確認する処理を作ります。
以下のコードを実行することで、結果を得られます。
環境によってはSSLのSubjectAltNameWarningを表示され場合がありますが、一時的にwarningを非表示にするには、SSLのSubjectAltNameWarningを非表示にする場合は追記
の部分をコメントインしてください。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import logging
import hdfs
from hdfs import Config
# SSLのSubjectAltNameWarningを非表示にする場合は追記
'''
import requests
from requests.packages.urllib3.exceptions import SubjectAltNameWarning
requests.packages.urllib3.disable_warnings(SubjectAltNameWarning)
'''
# logger
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
try:
'''
https://prod.namenode:port/webhdfs/v1/ の下から定義する
~/.hdfscli.cfgのrootの定義によって変わる
'''
path = 'user/sample'
'''
~/.hdfscli.cfgで定義した環境のdev, prodのどちらかを入力
prodを指定した場合、これだけでkerberos認証になる
'''
client = Config().get_client('prod')
result = client.list(path)
logger.debug(result)
except hdfs.util.HdfsError as e:
logger.error(str(e))
requestsパッケージでWebHDFS REST APIを叩く方法
こちらはhdfsパッケージは使わずに、requestsパッケージでWebHDFS REST APIを叩く方法です。
サンプルコード
以下もディレクトリの中身を確認する処理です。
こちらを実行することで結果が得られます。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import logging
import os
import requests
from requests_kerberos import HTTPKerberosAuth
# SSLのSubjectAltNameWarningを非表示にする場合は追記
'''
from requests.packages.urllib3.exceptions import SubjectAltNameWarning
requests.packages.urllib3.disable_warnings(SubjectAltNameWarning)
'''
# logger
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
method = 'GET'
url = 'https://prod.namenode:port/webhdfs/v1/user/sample?op=liststatus'
session = requests.Session()
response = session.request(
method=method,
url=url,
timeout=60,
headers={'content-type': 'application/octet-stream'},
# これが必要
auth=HTTPKerberosAuth()
)
logger.debug(response.status_code)
logger.debug(response.text)