# Utilities ## Conjur ::: info :bulb: **Summary** **Conjur** adalah sistem client/server yang mempermudah manajemen rahasia seperti username/password antar aplikasi untuk meningkatkan lapisan sekuritas aplikasi. ::: ### Brief Explanation #### Conjur Client Client akan meminta rahasia (secrets) yang disimpan di conjur server dengan cara meminta nilai dari secrets variable yang telah disetujui oleh conjur server. #### Conjur Server Server akan memberikan rahasia (secrets) ke conjur client yang telah terotentikasi dengan server sesuai dengan secrets variable yang diminta. #### Secrets Variable Parameter yang akan digunakan untuk ditukar dengan rahasia yang disimpan di server conjur. --- ### Implementation ::: info :bulb: **Summary** Pada Visualization Engine, **conjur** digunakan untuk menyimpan rahasia seperti username/password database pada conjur server & worker disini bertindak sebagai conjur client. ::: #### Environment Variables Untuk membangun koneksi dari conjur client ke conjur server, diperlukan beberapa parameter seperti berikut: | Parameter | Description | | ----------------------- | ---- | | CONJUR_SSL_CERTIFICATE | Sertifikat SSL | | CONJUR_AUTHN_TOKEN_FILE | Token otentikasi untuk memanggil API ke conjur server | | CONJUR_APPLIANCE_URL | Alamat host conjur server | | CONJUR_ACCOUNT | ID account | ::: info :pencil: **Note** Seluruh parameter diatas disediakan oleh environment deployment sebagai **ENVIRONMENT VARIABLES**. ::: #### Conjur Client ::: danger :warning: Implementasi Conjur di Python 3.8 menggunakan library **conjur** versi 7.0.1 ::: * Fungsi **get_conjur_client** berfungsi menginisialisasi API client menggunakan parameter-parameter yang telah diberikan * Line 8 menginisialisasi API Client * Line 9 mencantumkan API Token * Line 11 memanggil API sederhana ke conjur server (seperti **ping**) ```python= from conjur import Api def get_conjur_client(conjur_config, api_token) -> Api: try: if api_token == '': raise Exception("Conjur API Token file is empty") Log.info(f"CONJUR API CLIENT: establishing connection to {conjur_config['url']}") client = Api(**conjur_config) client._api_token = api_token client.api_token_expiration = datetime.now() + timedelta(minutes=client.API_TOKEN_DURATION) client.whoami() # whoami hanya untuk ngetes koneksi ke conjur server Log.info(f"CONJUR API CLIENT: established to {conjur_config['url']}") Log.info("="*70) return(client) except Exception as exception: Log.error(f"""CONJUR API CLIENT: not established, please check the client configuration: {exception}""") raise exception ``` #### Load secrets * Fungsi load_secrets berfungsi menukarkan **secrets variable** ke **conjur server** dan dituliskan ke **config** yang akan dipakai aplikasi * Line 7 menjalankan fungsi **get_conjur_client** untuk inisialisasi API client * Line 11-14 memanggil API **get_variable** untuk mengambil **secrets** ke **conjur server** * Line 19-34 menuliskan nilai **secrets** ke **config** ```python= def load_secrets(config): ### ===========Truncated ============ # URL CHECK if not conjur_client_conf.get('url'): raise Exception("ENV_VAR CONJUR_APPLIANCE_URL is missing") conjur_api_client = get_conjur_client(conjur_client_conf, conjur_api_token) Log.info("CONJUR API CLIENT: FETCHING CONJUR SECRETS") try: kafka_usr = conjur_api_client.get_variable(config['producer_kafka']['sasl.username']) kafka_pass = conjur_api_client.get_variable(config['producer_kafka']['sasl.password']) db_usr = conjur_api_client.get_variable(config['postgres_db_dwh']['user']) db_pass = conjur_api_client.get_variable(config['postgres_db_dwh']['password']) except Exception as exception: Log.error(f"CONJUR API CLIENT: FAILED TO FETCH SECRETS: {exception}") raise Exception(f"API get_variables ERRROR: {exception}") else: config.get("producer_kafka").update({ "sasl.username": kafka_usr.decode('utf-8'), "sasl.password": kafka_pass.decode('utf-8') }) config.get("consumer_kafka").update({ "sasl.username": kafka_usr.decode('utf-8'), "sasl.password": kafka_pass.decode('utf-8') }) config.get("postgres_db_dwh").update({ "user": db_usr.decode('utf-8'), "password": db_pass.decode('utf-8') }) config.get("postgres_db_ext_dwh").update({ "user": db_usr.decode('utf-8'), "password": db_pass.decode('utf-8') }) return config ``` ## Consul & Vyper :::info :bulb: **Summary** **Consul** digunakan untuk centralized file configuration sehingga tidak perlu dicantumkan ke deployment container. ::: Applications can make use of Consul's hierarchical key/value store for any number of purposes, including dynamic configuration, feature flagging, coordination, leader election, and more. The simple HTTP API makes it easy to use.