Spring Boot Vault Secrets | HashiCorp Vault Sinhala Guide

Spring Boot Vault Secrets | HashiCorp Vault Sinhala Guide

ආයුබෝවන් යාළුවනේ!

අද අපි කතා කරන්න යන්නේ software engineering වලදී ගොඩක් වැදගත් වෙන, ඒ වගේම ගොඩක් අය මගහරින subject එකක් ගැන – ඒ තමයි Secrets Management. විශේෂයෙන්ම, අපි බලමු අපේ Spring Boot applications වල HashiCorp Vault එක කොහොමද secrets manage කරන්න use කරන්නේ කියලා. ඇත්තටම මේක ගොඩක් වටිනා skill එකක්, මොකද production වලදී අපේ application එකේ sensitive data, password, API keys වගේ දේවල් ආරක්ෂා කරගන්න එක අත්‍යවශ්‍යයි නේද?

මේ tutorial එක අවසානෙට, ඔයාට පුළුවන් වෙයි Spring Boot application එකක් HashiCorp Vault එක්ක integrate කරලා, secrets store කරලා, ඒවා application එක ඇතුලෙන් retrieve කරගන්න විදිහ ගැන හොඳ අවබෝධයක් ගන්න. එහෙනම්, අපි පටන් ගමු!

ඇයි Secrets Management වැදගත් වෙන්නේ?

හිතන්න ඔයා Spring Boot application එකක් හදනවා කියලා. මේ application එකට database එකකට connect වෙන්න, third-party API එකක් call කරන්න, එහෙමත් නැත්නම් වෙනත් service එකක් එක්ක communicate කරන්න ඕන වෙනවා. මේ හැම එකකටම credentials (username, password, API keys, tokens) වගේ sensitive data ඕන වෙනවා නේද?

සාමාන්‍යයෙන් මේවා manage කරන්නේ කොහොමද? ගොඩක් වෙලාවට, developersලා මේ secrets ටික code එක ඇතුලෙම (hardcode) කරනවා, එහෙමත් නැත්නම් application.properties/application.yml වගේ configuration files වල දානවා. මේ ක්‍රම දෙකම security පැත්තෙන් ගොඩක් අවදානම්. ඇයි?

  • Hardcoding: Code එක GitHub වගේ public repository එකක තිබ්බොත්, ඔයාගේ secrets ටික ඕන කෙනෙක්ට බලාගන්න පුළුවන්. ඒ වගේම, secret එකක් වෙනස් කරන්න ඕන වුණොත්, code එක compile කරලා redeploy කරන්න වෙනවා.
  • Configuration Files: මේවා version control system එකක තිබ්බොත්, ඒකත් hardcoding වගේම අවදානම්. Servers වල තිබ්බත්, ඒවාට access තියෙන කෙනෙක්ට secrets බලාගන්න පුළුවන්.

මේ ප්‍රශ්නෙට හොඳම විසඳුම තමයි dedicated Secrets Management System එකක් පාවිච්චි කරන එක. මේ වගේ system එකකින් අපිට පුළුවන් secrets ටික centralize කරලා, secure විදිහට store කරලා, access control rules දාලා, ඒවාට access කරන හැම වෙලාවෙම audit log එකක් තියාගන්න. මේකට තියෙන ජනප්‍රියම විසඳුමක් තමයි HashiCorp Vault.

HashiCorp Vault කියන්නේ මොකක්ද?

HashiCorp Vault කියන්නේ HashiCorp සමාගම විසින් හදපු, secrets ආරක්ෂිතව store කරන්න, access කරන්න, automate කරන්න සහ audit කරන්න පුළුවන් tool එකක්. ඒක ගොඩක් flexible, scalable, සහ secure. Vault වල ප්‍රධාන Features කිහිපයක් මෙන්න:

  • Secure Storage: Key-value store, databases, cloud platforms වගේ තැන්වල secrets encrypt කරලා store කරනවා.
  • Dynamic Secrets: Database credentials, cloud API keys වගේ දේවල් request කරන වෙලාවටම generate කරලා, කලින් define කරපු lifespan එකකින් පස්සේ revoke කරන්න පුළුවන්. මේකෙන් attack surface එක අඩු වෙනවා.
  • Leasing & Renewal: Secrets වලට lifespan එකක් තියෙනවා. ඒ කාලය ඉවර වුණාම revoke වෙනවා. Application එකට ඕන නම්, secret එක renew කරන්නත් පුළුවන්.
  • Access Control: Fine-grained policies හරහා, කාටද මොන secret එකටද access කරන්න පුළුවන් කියන එක define කරන්න පුළුවන්.
  • Auditing: Vault එකට කරන හැම request එකක්ම log වෙනවා. මේකෙන් security audit කරන්න ලේසියි.
  • Encryption as a Service: Secrets වලට අමතරව, data encrypt/decrypt කරන්නත් Vault use කරන්න පුළුවන්.

මේ වගේ වාසි නිසා තමයි production environments වල Vault මෙච්චර ජනප්‍රිය.

Vault Local එකේ Setup කරගමු

අපිට මේ tutorial එකට Vault එක local machine එකේ run කරන්න පුළුවන්. ඒකට ලේසිම විදිහ තමයි Development Mode එක use කරන එක. මේ mode එක production වලට සුදුසු නැහැ, හැබැයි test කරන්න හොඳයි. අපි Docker use කරමු, එහෙම නැත්නම් direct binary එක download කරගන්නත් පුළුවන්.

Docker වලින් Vault Run කරන හැටි:

ඔයාගේ machine එකේ Docker install කරලා නැත්නම්, මුලින්ම ඒක install කරගන්න.

docker run --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' -p 8200:8200 --name dev-vault hashicorp/vault:latest vault server -dev -dev-listen-address="0.0.0.0:8200"

මේ command එකෙන් වෙන්නේ:

  • --cap-add=IPC_LOCK: Vault ටිකක් secure වෙන්න මේ capability එක ඕන වෙනවා.
  • -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot': Development token එක myroot විදිහට සෙට් කරනවා. මේක තමයි අපිට Vault access කරන්න ඕන වෙන token එක.
  • -p 8200:8200: Local machine එකේ 8200 port එක, Docker container එකේ 8200 port එකට map කරනවා. Vault default විදිහට run වෙන්නේ මේ port එකේ.
  • --name dev-vault: Container එකට නමක් දෙනවා.
  • hashicorp/vault:latest: HashiCorp Vault Docker image එක.
  • vault server -dev -dev-listen-address="0.0.0.0:8200": Vault development server එක start කරනවා.

Container එක run වුණාම, ඔයාට මේ වගේ output එකක් බලාගන්න පුළුවන්:

...
==> Vault server started! Log data will stream in below:

     Address: http://0.0.0.0:8200
     Root Token: myroot
     Vault Mode: Development

...

Root Token: myroot කියන එක හොඳට මතක තියාගන්න. මේක අපිට Spring Boot configure කරනකොට ඕන වෙනවා.

දැන් Vault server එක run වෙනවා. ඊළඟට අපිට මේකට secrets දාන්න පුළුවන්. අපි command line එකෙන් secrets දාමු.

අලුත් terminal එකක් open කරලා, පහත command එක execute කරන්න. මේකට Vault CLI tool එක install කරලා තියෙන්න ඕන. නැත්නම්, Docker container එක ඇතුලට ගිහින් run කරන්න පුළුවන්:

# Docker container එක ඇතුලට යන්න
docker exec -it dev-vault /bin/sh

# Vault CLI environment variables set කරන්න
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='myroot'

# Secret එකක් දාමු
vault kv put secret/my-app/config username=appuser password=appsecret

මේ command එකෙන් වෙන්නේ secret/my-app/config කියන path එකට username සහ password කියන secrets දාන එක. secret/ කියන්නේ Vault වල default secrets engine එකේ path එක. අපිට my-app/config වගේ custom paths හදාගන්න පුළුවන්.

සාර්ථකව secret එක දැම්මම, මේ වගේ output එකක් එනවා:

Key              Value
---
created_time     2023-10-27T10:00:00.123456Z
deletion_time    n/a
destroyed        false
version          1

Integrating Spring Boot with Vault

දැන් අපේ Vault server එක run වෙනවා, secrets ටිකත් දාලා තියෙන්නේ. ඊළඟට, අපේ Spring Boot application එක මේ Vault එක්ක සම්බන්ධ කරගමු. මේකට අපි Spring Cloud Vault Config dependency එක use කරනවා.

Maven Dependencies:

ඔයාගේ pom.xml එකට මේ dependency එක එකතු කරන්න:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>

ඒ වගේම, Spring Cloud dependencies ටික manage කරන්න spring-cloud-dependencies BOM එක dependencyManagement section එකට එකතු කරන්න ඕන:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2022.0.4</version> <!-- Replace with your Spring Cloud version -->
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

version එක ඔයා use කරන Spring Boot version එකට ගැලපෙන Spring Cloud version එකක් දාන්න. Spring Boot version table එකක් Spring Cloud docs වල හොයාගන්න පුළුවන්.

Spring Boot Configuration:

දැන් අපේ Spring Boot application එකට Vault connect කරන්න ඕන කරන configuration ටික application.properties (නැත්නම් application.yml) එකට දාමු.

src/main/resources/bootstrap.properties (හෝ bootstrap.yml) කියන file එක හදලා, මේ ටික එකතු කරන්න:

spring.application.name=my-app-vault-demo
spring.config.import=optional:vault://

spring.cloud.vault.scheme=http
spring.cloud.vault.host=127.0.0.1
spring.cloud.vault.port=8200
spring.cloud.vault.token=myroot
spring.cloud.vault.kv.enabled=true
spring.cloud.vault.kv.default-context=application
spring.cloud.vault.kv.application-name=my-app
spring.cloud.vault.generic.backend=secret
spring.cloud.vault.generic.default-context=secret

මේ properties ටික ගැන පොඩ්ඩක් බලමු:

  • spring.application.name=my-app-vault-demo: අපේ application එකේ නම. Vault එක secrets කියවනකොට මේ නම use කරනවා.
  • spring.config.import=optional:vault://: Spring Boot 2.4+ වලදී external configurations import කරන්න මේක use කරනවා. Vault එකේ secrets load කරන්න මේක අත්‍යවශ්‍යයි.
  • spring.cloud.vault.scheme=http, spring.cloud.vault.host=127.0.0.1, spring.cloud.vault.port=8200: Vault server එකේ address එක. අපේ Docker setup එකට මේවා හරි.
  • spring.cloud.vault.token=myroot: Vault access කරන්න ඕන token එක. Development mode එකේදී අපිට ලැබුණ myroot token එක තමයි මේක. Production වලදී මේක වෙනස් වෙනවා (e.g., AppRole, Kubernetes Service Account).
  • spring.cloud.vault.kv.enabled=true: Key-Value secrets engine එක enable කරනවා.
  • spring.cloud.vault.kv.default-context=application: Spring Cloud Vault විසින් secrets සොයන default context එක. මේක application කියන්නේ application නම. ඒ කියන්නේ, Vault එකේ secret/application සහ secret/my-app-vault-demo වගේ paths වල secrets හොයනවා.
  • spring.cloud.vault.kv.application-name=my-app: Vault එකේ secrets path එකේ application part එක. ඒ කියන්නේ secret/my-app/config වගේ paths වලට map වෙනවා.
  • spring.cloud.vault.generic.backend=secret: Vault එකේ /secret කියන path එකේ තියෙන KV engine එක use කරන්න කියන එක.

Note: bootstrap.properties file එක වැදගත් වෙන්නේ Spring Cloud Context එක initialisation වෙනකොටම Vault secrets load කරන්න ඕන නිසා. application.properties එකට දැම්මොත්, සමහර වෙලාවට secrets load වෙන්න කලින් application context එක හැදෙන්න පුළුවන්.

Storing and Retrieving Secrets

දැන් අපේ Spring Boot application එක Vault එක්ක connect වෙලා තියෙන්නේ. අපි කලින් vault kv put secret/my-app/config username=appuser password=appsecret කියලා secret එකක් දැම්මා නේද? දැන් අපි බලමු ඒ secrets ටික Spring Boot application එක ඇතුලෙන් retrieve කරගන්නේ කොහොමද කියලා.

Spring Boot Application Code:

අපි මේ secrets read කරලා console එකේ print කරන්න සරල Spring Boot application එකක් හදමු.

මුලින්ම, MyVaultApplication.java (ඔයාගේ main class එක) එක හදාගමු:

package com.example.vaultdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SpringBootApplication
public class MyVaultApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyVaultApplication.class, args);
    }
}

@Component
class VaultSecretReader {

    private static final Logger log = LoggerFactory.getLogger(VaultSecretReader.class);

    @Value("${username}")
    private String dbUsername;

    @Value("${password}")
    private String dbPassword;

    @EventListener(ApplicationReadyEvent.class)
    public void readSecrets() {
        log.info("------------------------------------------");
        log.info("Retrieved username from Vault: {}", dbUsername);
        log.info("Retrieved password from Vault: {}", dbPassword);
        log.info("------------------------------------------");
    }
}

මේ code එකේ වෙන්නේ මොකක්ද කියලා බලමු:

  • @SpringBootApplication: Standard Spring Boot application annotation.
  • @Component: VaultSecretReader class එක Spring component එකක් විදිහට define කරනවා, ඒක Spring context එකට load වෙනවා.
  • @Value("${username}") සහ @Value("${password}"): මේ annotations වලින් වෙන්නේ Vault එකෙන් load වෙච්ච username සහ password කියන properties, අපේ dbUsername සහ dbPassword variables වලට map කරන එක. Spring Cloud Vault, Vault එකෙන් secrets load කරලා ඒවා Spring Environment එකට expose කරනවා, ඒ නිසා අපිට මේ වගේ @Value annotations වලින් ඒවාට access කරන්න පුළුවන්.
  • @EventListener(ApplicationReadyEvent.class): Application එක සම්පූර්ණයෙන්ම ready වුණාට පස්සේ, readSecrets() method එක execute කරන්න මේක use කරනවා. මේ වෙද්දී Vault secrets load වෙලා ඉවරයි.
  • log.info(...): Secrets console එකේ print කරනවා.

Run කරලා බලමු!

දැන් අපේ Spring Boot application එක run කරන්න. ඔයාට පුළුවන් IDE එකෙන් run කරන්න, එහෙමත් නැත්නම් Maven එකෙන් run කරන්න:

mvn spring-boot:run

Application එක start වෙනකොට, ඔයාට console එකේ මේ වගේ output එකක් බලාගන්න පුළුවන් වෙයි:

...
INFO  com.example.vaultdemo.VaultSecretReader  : ------------------------------------------
INFO  com.example.vaultdemo.VaultSecretReader  : Retrieved username from Vault: appuser
INFO  com.example.vaultdemo.VaultSecretReader  : Retrieved password from Vault: appsecret
INFO  com.example.vaultdemo.VaultSecretReader  : ------------------------------------------
...

ආ... වැඩේ හරි නේද? අපේ Spring Boot application එකට පුළුවන් වුණා Vault එකේ තිබ්බ secrets ආරක්ෂිතව retrieve කරගන්න. දැන් අපිට මේ secrets application එක ඇතුලෙදී database connections, API calls වගේ දේවල් වලට use කරන්න පුළුවන්.

Best Practices (හොඳම Practices)

මේ tutorial එකේ අපි Vault development mode එකයි, root token එකයි use කළේ ඉක්මනට පටන් ගන්න. හැබැයි production environment එකකදී මේවා ගොඩක් භයානකයි. Production වලදී මේ දේවල් මතක තියාගන්න:

  • Authentication Methods: Production වලදී VAULT_TOKEN එක hardcode කරනවා වෙනුවට, AppRole, Kubernetes Service Account, AWS IAM, Azure Active Directory වගේ authentication methods use කරන්න. මේවා වඩාත් secure සහ automate කරන්න ලේසියි.
  • TLS/SSL: Vault server එකට connect වෙනකොට HTTP වෙනුවට HTTPS (TLS/SSL) use කරන්න. Secrets network එකේ යනකොට encrypt වෙලා තියෙන්න ඕන.
  • Vault Unsealing: Production Vault server එකක් start කරනකොට "sealed" state එකේ තමයි තියෙන්නේ. ඒක "unseal" කරන්න keys කිහිපයක් එකතු කරන්න ඕන. මේ keys ආරක්ෂිතව තියාගන්න එක ගොඩක් වැදගත්. Auto-unseal කරන්න cloud KMS (Key Management Service) වගේ දේවල් use කරන්න පුළුවන්.
  • Least Privilege: Application එකට අවශ්‍ය secrets වලට පමණක් access දෙන්න. අනවශ්‍ය secrets වලට access දෙන්න එපා.
  • Auditing: Vault වල audit logs නිතරම review කරන්න. මේකෙන් security breaches detect කරන්න පුළුවන්.
  • Dynamic Secrets: පුළුවන් නම් dynamic secrets use කරන්න. මේවා කෙටි කාලයකට generate කරලා revoke කරන නිසා security posture එක වැඩි වෙනවා.

නිගමනය

ඉතින් යාළුවනේ, අපි මේ tutorial එකෙන් Spring Boot applications වල HashiCorp Vault integrate කරලා secrets manage කරන හැටි ඉගෙනගත්තා. Secrets hardcode කරනවාට වඩා, මේ වගේ dedicated secrets management system එකක් use කරන එක security පැත්තෙන් ගොඩක් වැදගත් කියලා ඔයාට දැන් තේරෙනවා ඇති.

ඔයාගේ මීළඟ Spring Boot project එකේදී මේ concepts try කරලා බලන්න. Secrets secure විදිහට manage කරන එක, software engineering වලදී ඔයාට තියෙන්නම ඕන skill එකක්. මොකද, security කියන්නේ අමතක කරන්න බැරි දෙයක් නේද?

මේ ගැන ඔයාගේ අදහස්, ප්‍රශ්න තියෙනවා නම් පහලින් comment කරන්න. අපි එකතු වෙලා මේ දැනුම තවත් දියුණු කරගමු!

තවත් අලුත් දෙයක් එක්ක හමුවෙමු, හැමෝටම ජය!