---
# System prepended metadata

title: Utilities

---

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

