# 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.