[Azure Function]Ensuring Azure Function App is Running Before Deployment

프로덕션 환경에서 Azure Function App을 배포할 때, 앱의 상태를 확인하는 것은 매우 중요하다. 만약 Azure Function App의 상태가 ‘Runing’이 아니라면 배포가 되지 않는다.

Azure DevOps와 Azure CLI를 사용해 Function App의 상태를 확인하고, 앱이 실행 중이지 않다면 시작해야한다. 이 간단한 스크립트를 통해 배포 오류를 방지하고 원활한 운영을 보장할 수 있습니다.

Azure DevOps 작업 구성

- task: AzureCLI@2
  inputs:
    azureSubscription: ' Your Azure subscription details' 
    scriptType: 'bash'
    scriptLocation: 'inlineScript'
    inlineScript: |
      state=$(az functionapp show --resource-group $(resourceGroupName) --name $(functionAppName) --slot second --query "state" -o tsv)
      if [ "$state" != "Running" ]; then
        echo "Function App is not running. Starting the Function App..."
        az functionapp start --resource-group $(resourceGroupName) --name $(functionAppName) --slot second
      else
        echo "Function App is already running."
      fi

[Azure SQL]Using Always Encrypted with .NET (feat. Keyvault)(2)

[Azure SQL]Using Always Encrypted with .NET (feat. Keyvault)(1)에서 SQL에 Always Encryted가를 설정하여 데이터를 암호화하고 쿼리하는 방법에 대해서 알아봤다. 이번 포스트에서는 Always Encryted가 설정된 SQL를 이용하여 .Net 서비스를 개발하는 방법에 대해서 알아보겠다.

.Net 서비스 내에서 Always Encrypted가 설정된 SQL에 접근 하기 위해서는 Connection String에 아래 옵션이 설정 되어야 한다.

  • Encryption Setting=Enabled
  • Encrypt=True

appsettings.json에서 ConnectionStrings에 다음과 같이 설정하면 된다.

"ConnectionStrings": {
  "DefaultConnection": "Server=tcp:azure sql.database.windows.net,1433;Initial Catalog=DB;Persist Security Info=False;User ID={user id};Password={password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Column Encryption Setting=Enabled;"
}

여기까지 하면 db connection이 생성될 때 Always Encryed 설정이 활성화 된다. 하지만 CEK가 설정된 Table을 읽어 오지는 못한다. 제대로 값을 읽어 오기 위해서는 CEK Provider를 서비스 시작 시점에 설정을 해주어야 한다.

CEK Provider는 Program.cs에 다음과 같이 Provider를 구성해주면 된다.

var azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new DefaultAzureCredential());

var dics = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
dics.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);

SqlConnection.RegisterColumnEncryptionKeyStoreProviders(dics);

이제, 아래와 같이 간단히 앞서 암호화 했던 Users 테이블을 select해 보면 복호화 된 데이터를 확인 할 수 있다.

await using var conn = (SqlConnection)_context.Database.GetDbConnection();

await conn.OpenAsync();

await using var cmd = new SqlCommand("select * from Users", conn);
await using var reader = await cmd.ExecuteReaderAsync();

await reader.ReadAsync();

var result = $"{reader[0]}, {reader[1]}, {reader[2]}";
//id, email, name, registered date
//1, abc@gmail.com, abc, 2023-01-01 00:00.000

[Azure SQL]Using Always Encrypted with .NET (feat. Keyvault)(1)

데이터를 저장 및 관리 하다 보면, 민감한 정보를 아무나 볼 수 없도록 식별 불가능하게 하도록 비식별화 작업을 해야 할 때가 있다.

데이터 비식별화를 하는 방법은 여러가지가 있지만, 그 중에서 데이터를 암호화하는 방법을 Azure SQL의 Always Encrypted 기능을 사용해서 구현해보려고 한다.

Always Encryted 기능은 Azure SQL에 저장된 민감한 데이터를 암호화 시킬 수 있고, 암호화에 사용된 암호화 키를 DB engine과 공유하지 않기 때문에 권한이 있는 클라이언트만 실제 데이터를 확인 할 수 있다. 그래서 권한에 따라서 데이터를 볼 수 있는 사람과 없는 사람을 명확히 구분할 수 가 있게 된다.

구성 방법

Always Encryted 기능을 사용하기 위해서는 2가지 키가 필요하다.

  1. Column master key(CMK)
    • Column encryption key들을 암호화하는데 사용된다.
    • HSM 모듈을 사용해서 생성하고 Azure Keyvault에 저장한다.
  2. Column encrytion key(CEK)
    • Table의 특정 Column data를 암호화 하거나 복호화 하는데 사용된다.
    • 각 Column 별로 독립적으로 관리된다.

Create CMK

keyvault서비스에서 Key menu에서 Generate/Import 메뉴를 클릭한다.

사용할 RSA 키 정보를 입력하고 키를 생성한다.

  • Name: always-encryted-hsm
  • Key Type: RSA
  • Key Size: 3072

SQL Server Management Studio(SSMS)를 실행시킨다.
Object Explore에서 DB Instance를 선택하고, Security 폴더로 이동한다.
Always Encryted Key 폴더 밑에 Column master key폴더를 우클릭하여 master key 추가 메뉴를 클릭한다.

key store를 auzre keyvault를 선택하면, AAD Login을 해야한다. 정상적으로 로그인 하게 되면, subscription과 keyvault 리소스를 선택할 수 있다. 위에서 만든 RSA 키 정보를 찾아서 추가해준다.

여기까지 하면 Column master key가 생성된 것을 확인 할 수 있다.

Create CEK

이제 암호화를 대상이 되는 테이블을 우클릭 하면 Column Encryption key를 추가할 수 있는 메뉴를 확인 할 수 있다.

암호화를 해야 하는 Column들을 선택하고 위에서 만들 Master key를 사용해서 Column들을 암호화 한다.

이제 Table을 조회해 보면 해당 Column(email, name)의 정보가 식별할 수 없도록 암호화된 것을 확인 할 수 있다.

이 정보를 다시 복호화 하기 위해서는 SQL master 계정이나 Keyvault에 Cryptographic Operations 권한이 있는 계정을 사용해야 하며 Connection 정보에 “Column Encryption Setting = Enabled” 옵션을 추가해서 접근을 하면 복호화된 정보를 얻을 수 있다.

Next: [Azure SQL]Using Always Encrypted with .NET (feat. Keyvault)(2)

[Databricks] Get configuration profile

Databricks CLI를 사용할 때, 인증을 갱신을 해야 할 때가 있다.

databricks configure --host "<databricks host https://>" --token

PAT(Personal Access Token)을 입력하라고 나오는데 Databricks workspace에서 발급한 user token을 입력해 주면 된다.

Input Personal aceess token

인증이 갱신 되었다면, Databricks CLI가 정상 동작 할 것이다.

databricks secrets list-scopes

[Databricks] Using Azure Key Vault

Databricks에서 작업을 할 때 외부 데이터 소스를 가져와야 할 때가 있다. 이럴 때 외부 데이터 에 접근하기 위해서 연결 정보( ID, Password 등)가 필요하게 되는데, 이 정보는 작업자 외에 유출되면 안되는 경우가 있다.

이런 유출에 민감한 정보를 다뤄야 할 때, Secret manager 서비스를 사용하면 좋고, 이번 포스트에서는 Azure에서 제공하는 Key Vault 서비스를 사용해서 Databricks에서 민감정보를 다루는 방법을 알아보겠다.

먼저, Azure Key Vault 리소스를 생성하고 Secret에 연결 정보(SQL Connection string)를 등록한다.

이제 Databricks에서 Key Vault에 등록된 정보를 사용하기 위해서 secret scope를 만든다.

databricks secrets create-scope --scope databricks-secrets01 --scope-backend-type AZURE_KEYVAULT --resource-id /subscriptions/<subscription Id>/resourceGroups/<resource group name>/providers/Microsoft.KeyVault/vaults/databricks-secrets01 --dns-name https://databricks-secrets01.vault.azure.net/

잘 만들어 졌는지 아래 scope list 명령어로 확인해 본다.

databricks secrets list-scopes
Scope                 Backend         KeyVault URL
--------------------  --------------  ---------------------------------------------
databricks-secrets01  AZURE_KEYVAULT  https://databricks-secrets01.vault.azure.net/

이제 Databricks에서 Key Vault에 등록된 Secret 값을 사용하기 위한 준비 작업은 끝났다.
Workspace에서 notebook을 하나 만들고 아래 script 처럼 secret 값을 불러와 사용해보자.

jdbcUrl = dbutils.secrets.get(scope="databricks-secrets01", key="databricks-jdbc-url")
connectionProperties = {
  "user": dbutils.secrets.get(scope="databricks-secrets01", key="databricks-user"),
  "password": dbutils.secrets.get(scope="databricks-secrets01", key="databricks-password")
}

위 방식대로 불러온 값들은 변수에 저장되지만 databricks 내에서는 확인 할 수 없다.

값을 확인하기 위해서 print를 해보면 “REDACTED”라고 출력되는 것을 확인 할 수 있다.
하지만 해당 변수를 이용해서 실행시켜보면 정상 동작한다.

df = spark.read.jdbc(url=jdbcUrl, table='sys.objects', properties=connectionProperties)
df.show(2)

+----------+---------+------------+---------+----------------+----+------------+--------------------+--------------------+-------------+------------+-------------------+
|      name|object_id|principal_id|schema_id|parent_object_id|type|   type_desc|         create_date|         modify_date|is_ms_shipped|is_published|is_schema_published|
+----------+---------+------------+---------+----------------+----+------------+--------------------+--------------------+-------------+------------+-------------------+
| sysrscols|        3|        null|        4|               0|  S |SYSTEM_TABLE|2023-03-30 17:00:...|2023-03-30 17:00:...|         true|       false|              false|
|sysrowsets|        5|        null|        4|               0|  S |SYSTEM_TABLE|2009-04-13 12:59:...|2023-03-30 17:00:...|         true|       false|              false|
+----------+---------+------------+---------+----------------+----+------------+--------------------+--------------------+-------------+------------+-------------------+

이렇게 Azure Key Vault를 이용하면 Databricks에서 민감정보를 다뤄야 할 때, 실제 값을 보여주지 않으면서 script는 정상 동작 시킬 수 있다.

마지막으로, 사용하는 key vault에 있는 민감정보 값들이 더 이상 필요 없어진다면 해당 key vault에 접근 할 수 없도록 하는 것이 바람직하다. delete scope로 더 이상 사용 할 수 없도록 scope를 제거 할 수 있다.

 databricks secrets delete-scope --scope databricks-secrets01

[Logstash on K8S] Azure SQL to ElasticSearch

Azure SQL(이하 sql)의 data를 ElasticSearch(이하 es)로 검색을 하기 위해서 sql 데이터를 es의 index로 옮겨야 한다. 데이터를 옮기는 방법은 여러가지 방법이 있지만 일반적으로 많이 쓰이는 데이터 처리 오픈소스인 Logstash를 사용하여 옮기는 방법을 알아보자.

 Logstash를 운영하는 방식도 다양하지만 간단하게 사용하려면 역시 K8S만 한 것이 없기 때문에 K8S에 구성해보자.

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: logstash-configmap-start
  namespace: search
  labels:
    task: sql-search-init    
data:
  start.sh: |
    #!/bin/bash
    curl -L -O https://go.microsoft.com/fwlink/?linkid=2203102
    tar -xvf ./sqljdbc_11.2.0.0_kor.tar.gz
    mv ./sqljdbc_11.2/enu/mssql-jdbc-11.2.0.jre11.jar ./lib/mssql-jdbc-11.2.0.jre11.jar
  • start.sh 에서는 jdbc 드라이버를 셋팅하는 작업을 수행한다. 이 링크에서 항상 최신 버전의 jdbc 드라이버를 확인하는 것을 권장한다.
apiVersion: v1
kind: ConfigMap
metadata:
  name: logstash-configmap
  namespace: search
  labels:
    task: sql-search    
data:
  logstash.yml: |
    http.host: "127.0.0.0"
    path.config: /usr/share/logstash/pipeline
  logstash.conf: 
    input {
      jdbc {
        jdbc_driver_library => "/usr/share/logstash/lib/mssql-jdbc-11.2.0.jre11.jar"
        jdbc_driver_class => "com.microsoft.sqlserver.jdbc.SQLServerDriver"
        jdbc_connection_string => "jdbc:sqlserver://{database server}:1433;database={Database name};encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"
        jdbc_user => "{user}"
        jdbc_password => "{password}"
        statement => "{SQL Query statement};"        
        schedule => "{CRON}"
        tracking_column => "{tracking column}"
        
      }
    }    
    output {
      elasticsearch {
        hosts => "{elastic host}"
        index => "{index name}"
        document_id => "%{index id name}"
        user => elastic
        password => "{elastic password}"
      }
      stdout {
        codec => rubydebug
      }
    }
  • input
    • jdbc_connection_string 에서는 접속할 Azure SQL의 connection string을 넣어 주면된다.
    • jdbc_user SQL 접속 계정 정보 값을 넣어준다. logstash 전용 계정을 만들어 사용하는 것을 권장한다.
    • jdbc_password 계정 비밀번호 값을 넣어준다.
    • statement index에 담을 table 혹은 작성한 query를 넣어 준다.
    • schedule 얼마 만큼 반복 작업을 할 것인지 스케줄을 정한다. 표기는 CRON을 사용한다.
    • tracking_column 데이터 변경에 대한 기준이 되는 column을 넣어 준다 (ex. timestemp)
  • output
    • hosts elastic host 정보를 넣어준다.
    • index SQL정보를 저장할 index 이름
    • document_id 인덱스에 저장할 문서를 식별할 키 값
    • password elstic에 접속할 비밀번호

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sql-logstash
  namespace: search
spec:
  replicas: 1
  selector:
    matchLabels:
      task: sql-search      
  template:
    metadata:
      labels:
        task: sql-search        
    spec:
      containers:
      - name: logstash
        image: docker.elastic.co/logstash/logstash:8.4.2
        ports:
          - containerPort: 5044
        imagePullPolicy: Always
        volumeMounts:
        - mountPath: /usr/share/logstash/config
          name: config-volume
        - mountPath: /usr/share/logstash/pipeline
          name: logstash-pipeline-volume
        - mountPath: /start
          name: start
        lifecycle:
          postStart:
            exec:
              command:
               - /start/start.sh
      volumes:
      - name: config-volume
        configMap:
          name: logstash-configmap
          items:
          - key: logstash.yml
            path: logstash.yml
      - name: logstash-pipeline-volume
        configMap:
          name: logstash-configmap
          items:
          - key: logstash.conf
            path: logstash.conf
      - name: start
        configMap:
          name: logstash-configmap-start
          defaultMode: 0777
      securityContext:
        fsGroup: 101

Service

apiVersion: v1
kind: Service
metadata:
  labels:
    task: sql-search
    kubernetes.io/name: logstash
  name: sql-logstash
  namespace: search
spec:
  ports:
  - port: 5000
    targetPort: 5000
  selector:
    k8s-app: logstash

Configmap 부터 Service 까지 순서대로 모두 K8S에 적용해 주면 된다.
(여러 개의 파일로 보는 것이 귀찮다면 하나의 yaml에 모두 넣어서 한번에 실행해도 된다.)

Calculating DTU in AWS RDS for MSSQL

On-Prem이나 VM 형태로 사용하던 MSSQL Server를 Azure SQL로 Migration을 한다고 가정해보자. 기존에 사용하던 처리 성능에 맞춰 Cloud 상에 알맞은 수준의 리소스를 준비하고 옮겨야 할 것이다.

기존에 사용하던 SQL Server는 CPU와 Memory, Disk I/O등 Hardware적인 요소로 처리 성능을 나타낸다. 하지만 Azure SQL에서는 DTU(Database Throughput Unit)라는 단위를 사용하여 처리 성능을 나타내기 때문에 성능 비교가 쉽지가 않다.

DTU는 Hardware 성능 요소인 CPU, Disk I/O와 Database Log flush 발생양을 이용하여서 계산해낸 단위이다. 때문에 MSSQL Server에서 각 Metric들을 추출해 낼 수 있다면, DTU를 계산해 낼 수 있다. DTU 계산은 이미 Azure DTU Calculator라는 계산기가 제공되고 있기 때문에 추출해낸 Metric 값들을 설명대로 잘 넣어 주기만 하면 쉽게 확인해 볼 수 있다.

Metric을 추출하는 방법은 대상이 되는 SQL Server에서 DTU Calculator에서 제공하는 PowerShell Script를 관리자 권한으로 실행시켜 주기만 하면 된다. Script는 CPU, Disk I/O, Database Log flush에 대한 Metric들을 DTU Calculator에서 요구하는 형식으로 추출해준다. 때문에 일반적으로 On-Prem이나 VM 형태로 MSSQL Server를 사용하고 있다면, 계산해 내는데 별다른 어려움이 없을 것이다.

하지만 AWS RDS for MSSQL 같은 경우 MSSQL Server를 AWS에서 Cloud Service로 제공하기 위해 Wrapping한 서비스다보니 SQL Server에 대한 관리자 권한을 얻을 수가 없다. 이러한 이유 때문에 DTU Calculator에서 제공하는 PowerShell Script를 사용할 수 가 없다.

이런 경우, DTU 계산에 필요한 Metric들을 AWS에서 별도로 추출해야 한다. AWS에는 Cloudwatch라는 서비스를 제공하고 있는데, AWS 서비스들에 대한 Performance Metric을 기록하고 제공하는 역할을 한다.

Cloudwatch에서 metric을 추출하기 위해서는 AWS CLI를 사용하는 것이 편리하다. AWS Console의 우측 상단에 있는 CLI 실행 아이콘을 눌러 AWS CLI를 실행해 보자.

AWS CLI가 실행 되었다면, 아래 조회 명령어(list-metrics)를 실행시켜 제공되는 metric들에 대한 정보를 확인해 보자.

aws cloudwatch list-metrics --namespace AWS/RDS --dimensions Name=DBInstanceIdentifier,Value=[RDS for MSSQL Name]

잘 실행되었다면, cloudwatch에서 제공하는 Metric 리스트들을 확인 할 수 있다. 리스트 중 DTU계산에 필요한 CPU Processor Time과 Disk Reads/sec, Writes/sec에 값에 해당 하는 Metric 다음과 같다. (참고로, Log Bytes Flushed/sec에 해당하는 metric은 제공되지 않는다.)

{
    "Namespace": "AWS/RDS",
    "MetricName": "ReadIOPS",
    "Dimensions": [
        {
            "Name": "DBInstanceIdentifier",
            "Value": "[RDS for MSSQL Name]"
        }
    ]
},
{
    "Namespace": "AWS/RDS",
    "MetricName": "WriteIOPS",
    "Dimensions": [
        {
            "Name": "DBInstanceIdentifier",
            "Value": "[RDS for MSSQL Name]"
        }
    ]
},
{
    "Namespace": "AWS/RDS",
    "MetricName": "CPUUtilization",
    "Dimensions": [
        {
            "Name": "DBInstanceIdentifier",
            "Value": "[RDS for MSSQL Name]"
        }
    ]
}

이제, 필요한 metric 정보에 대해서 확인 하였으니 수집해보자. 아래 metric 수집 명령어(get-metric-statistics)를 사용하면 수집된 metric정보가 csv파일로 저장된다.

aws cloudwatch get-metric-statistics --namespace AWS/RDS --dimensions Name=DBInstanceIdentifier,Value=[RDS for MSSQL Name] --metric-name=CPUUtilization --period 3600 --statistics Average --start-time 2021-01-01T00:00:00.000Z --end-time 2021-02-01T00:00:00.000Z | jq -r '.Datapoints[] | [.Timestamp, .Average, .Unit] | @csv' | cat > cpu.csv

aws cloudwatch get-metric-statistics --namespace AWS/RDS --dimensions Name=DBInstanceIdentifier,Value=[RDS for MSSQL Name] --metric-name=ReadIOPS --period 3600 --statistics Average --start-time 2021-01-01T00:00:00.000Z --end-time 2021-02-01T00:00:00.000Z | jq -r '.Datapoints[] | [.Timestamp, .Average, .Unit] | @csv' | cat > read.csv

aws cloudwatch get-metric-statistics --namespace AWS/RDS --dimensions Name=DBInstanceIdentifier,Value=[RDS for MSSQL Name] --metric-name=WriteIOPS --period 3600 --statistics Average --start-time 2021-01-01T00:00:00.000Z --end-time 2021-02-01T00:00:00.000Z | jq -r '.Datapoints[] | [.Timestamp, .Average, .Unit] | @csv' | cat > write.csv

생성한 csv 파일은 AWS CLI Storage에 저장 되어있다. 우측 상단의 Actions > Download File 메뉴를 사용하면 로컬 환경으로 다운 받을 수 있다.

3개의 파일 모두 다운 받아서 DTU 계산에 필요한 형식으로 맞춰준다.

  • % Processor Time = CPUUtilization
  • Disk Reads/sec = ReadIOPS
  • Disk Writes/sec = WriteIOPS
  • Log Bytes Flushed/sec에 해당하는 데이터가 없기때문에 0으로 넣어준다.

그림과 같은 형태로 구성될 것이다.

RDS for MSSQL metrics for DTU Calculator

이제, 한땀 한땀 준비한 데이터를 Azure DTU Calculator에 넣어 주기만 하면 되는데 한가지 주의할 점이 있다. 우리가 얻은 데이터는 RDS for MSSQL Server에 대한 정보이다. 때문에 여러 DB Instance에 대한 계산을 하는 Elastic Database 메뉴를 선택하여 계산 하도록 해야한다.

계산이 끝나면 아래와 같이 나오는데 이 결과를 통해서 AWS RDS에서 사용하던 성능 수준을 Azure SQL에서 그대로 사용하기 위해서 구성 해야하는 Service Tire/Performance Level을 확인 할 수 있다.

DTU Result

Azure DevOps 개요

DevOps 란?

데브옵스(DevOps)는 소프트웨어의 개발(Development)과 운영(Operations)의 합성어로서, 소프트웨어 개발자와 정보기술 전문가 간의 소통, 협업 및 통합을 강조하는 개발 환경이나 문화를 말한다.

주로 아래 그림과 같이 개발과 운영간의 연속적인 사이클로 설명할 수 있다.

이를 통해서 얻는 장점은 다음과 같다.

  1. 신속한 제공
    • 릴리스의 빈도와 속도를 개선하여 제품을 더 빠르게 혁신하고 향상할 수 있다. 새로운 기능의 릴리스와 버그 수정 속도가 빨라질수록 고객의 요구에 더 빠르게 대응할 수 있다.
  2. 안정성
    • 최종 사용자에게 지속적으로 긍정적인 경험을 제공하는 한편 더욱 빠르게 안정적으로 제공할 수 있도록, 애플리케이션 업데이트와 인프라 변경의 품질을 보장할 수 있다.
  3. 협업 강화
    • 개발자와 운영 팀은 긴밀하게 협력하고, 많은 책임을 공유할 수 있도록, 워크플로를 결합한다. 이를 통해 비효율성을 줄이고 시간을 절약할 할 수 있다.
  4. 보안
    • 제어를 유지하고 규정을 준수하면서 신속하게 진행할 수 있다. 자동화된 규정 준수 정책, 세분화된 제어 및 구성 관리 기술을 사용할 수 있다.

그럼, DevOps를 실현하기 위해서는 어떻게 해야 하는가?

DevOps를 실현하기 위해서는 CI(Continuous Integration)/CD(Continuous Deployment(Delivery))라는 2가지 작업을 해야 한다.

CI(Continuous Integration)은 Development에 속하는 작업으로 지속적으로 프로젝트의 요구사항을 추적하며, 개발된 코드를 테스트 및 빌드를 수행한다.

  1. 프로젝트 기획 + 요구사항 추적
    • 프로젝트 시작
    • 기획(프로젝트 방법론 채택)
    • 작업관리(Backlog 관리)
    • 진행상황 추적
  2. 개발 + 테스트
    • 코드작성
    • 단위 테스트
    • 소스제어
    • 빌드
    • 빌드 확인

CD(Continuous Deployment(Delivery))는 Operations에 속하는 작업으로 CI가 완료되어 빌드된 소스를 통합 테스트(개발, QA, Staging)를 거쳐 배포를 하며, 배포된 사항들을 지속적으로 모니터링하고 프로젝트 요구사항에 피드백하는 작업을 수행한다.

  1. 빌드 + 배포
    • 자동화된 기능 테스트
    • 통합 테스트 환경(Dev)
    • 사전 제작 환경
      (QA, Load testing)
    • 스테이징 환경(Staging)
  2. 모니터링 + 피드백
    • 모니터링
    • 피드백

이제, DevOps를 하기위한 구체적인 작업을 알았으니, 실제 구성을 하도록 하는 제품들에 대해서 알아보자.

Azure DevOps vs Other Software

DevOps를 하기 위한 솔루션들은 이미 시중에 엄청나게 나와 있으며, 대게 오픈소스 형태로 많이 제공되고 있어서 바로 가져다 사용할 수 있다.

위 그림에서 볼 수 있듯이 DevOps의 각 단계에 맞추어서 원하는 (특화된)제품을 선택하여 사용하면 된다.

모든 단계를 빠짐 없이 구현한다고 가정하여, 예를 들면 다음과 같이 DevOps가 구현 될 수 있다.

  1. Slack으로 요구사항 관리를 하고
  2. Git으로 소스코드 관리를 하고
  3. Maven으로 빌드를 하고
  4. JUnit으로 테스트하고
  5. Jenkins로 Docker에 배포하고
  6. Kubernetes로 운영하며
  7. Splunk로 모니터링 한다.

그런데 이런 경우, 벌써 필요한 제품에 8개나 된다. 프로젝트에 참여하는 모든인원이 이 제품들에 대해서 이해하고 사용하기 어려우며, 각 제품에대한 담당자들있어야 제대로 운영 될 수 있을 것이다. 게다가, 각기 다른 제품이라 다음 단계로 넘어가기 위한 추가적인 관리를 해야할 것이다.

이렇게 되면, 규모가 작은 곳에서는 몇가지 단계를 건너띄고 관리를 하게 되는데 이런 부분에서 예외사항이 생기기 시작하고, 결국 프로젝트 끝에서는 DevOps를 거의하지 못하는 상황이 생길 수 도있다.

반면, Azure DevOps는 하나의 DevOps 관리 솔루션을 제공한다. 때문에 Azure DevOps 하나만 사용해도 모든 절차를 구성 할 수 있다.
그리고 만약, 기존에 사용하던 제품이 있다 하더라도 아래 그림과 같이 3rd-party를 마이그레이션 혹은 연동 설정 할 수 있도록 하기 때문에 Azure DevOps 제품안에서 하나로 통합 관리 할 수 있다.

마지막으로, Azure DevOps를 사용하는 간단한 시나리오에 대해서 알아보자.

Azure DevOps에서는 파이프라인이라는 형태로 CI/CD를 구성하도록 되어 있으며, 각 단계 구성은 아래 그림과 같다.

  1. Project (Agile) Board를 통해서 프로젝트 요구사항 추적 관리를 하고
  2. Repo에서 각 Agile Board Task에 대한 소스코드 관리를 하고
  3. 소스가 커밋이 되면 CI 파이프라인을 통해 빌드 + 테스트를 수행하고
  4. CI가 완료되면 Trigger 형태로 CD 파이프라인을 실행하고
  5. CD 파이프라인을 통해 통합 테스트 + 배포를 하고
  6. (옵션)담당자에게 최종 승인을 받고
  7. 운영 적용 및 모니터링을 한다.

Azure DevOps 이 외의 제품을 사용 했을 때와 단계는 거의 동일 하지만, 여기서 주목 할 점은 Azure DevOps 단일 제품에서 모두 제공 받고 구성 할 수 있다는 것이다.

(**여기서 다 설명 못한 부분이지만 CI/CD 과정 중에 Function(Trigger) 형태로 여러 기능들을 다양하게 엮을 수도 있다. 예를 들어 6번)

각각의 솔루션 전문가들이 있어서 운영한다면 문제가 없겠지만, DevOps를 처음 도입한다던가 규모가 작아 축소 운영을 해야하는 상황이라면 고려해 볼 수 있을 것 같다.

Azure Key Vault 개요

일반적으로, Application Security를 하기위해 Key Vault를 적용하는 사례/방법은 아래와 같이 크게 4가지가 있다.

  1. General Secret Storage
    • 다양한 종류의 비밀들을 저장 할 수 있다.
      (예, 민감한 환경설정, 데이터베이스 크리덴셜, API 키 등)
    • Plan Text file,프로젝트 환경설정 관리, DB에 저장 등, 보통 사용되는 방식 보다 Vault Read나 Vault API를 사용하여 Query하는 것이 훨씬 안전하다.
    • Vault의 Audit Log를 통해서 접근들을 보호 할 수 있다.
  2. Employee Credential Storage
    • General Secret Storage의 확장되는 개념이다.
    • 웹 서비스에 접근하는 직원들의 인증 정보를 저장하기 좋다.
    • Audit Log를 통해서 어떤 직원이 비밀에 접근(및 작업) 했는지 쉽게 알 수 있다.
  3. API Key Generation for Scripts
    • 이상적인 Vault의 기능인 “Dynamic Secrets” 을 통해서 비밀에 접근하는 키를 일정 기간동안 생성하고 만료 시킬 수 있다.
    • Keypair는 스크립트 동작으로만 존재 하며, 키의 생성 작업은 완벽하게 로그로 남는다.
    • IAM(Identity Access Management) 사용 이상의 기술이지만, 때로는 하드코딩으로 접근 제한을 두는 것이더 효율 적일 수 있다.
  4. Data Encryption
    • Vault를 사용하여 비밀을 저장할 수있을뿐만 아니라 다른 곳에 저장된 데이터를 암호화/복호화 할 수 있다.
    • 이 것을 사용하면 응용 프로그램이 기본 데이터 저장소에 데이터를 저장하면서 데이터를 암호화를 할 수 있다.

Azure Key Vault와 같은 서비스는 Azure에만 있는 것은 아니고 대부분의 클라우드 서비스에서 데이터 암화에 대한 KMS(Key Management Service)를 제공하고 있다. 그러면 이러한 서비스이 어떤 차이 점이 있는지 알아보자

AWS KMS(Amazon Web Service Key Management Service)

  • 암호화 표준은 RSA-OAEP와 PKCS#1v1.5(현재 2.2까지 나왔음.)를 사용한다.
  • CMK(Customer Master Key)와 Data Key를 이용하여 데이터를 암호화 작업을 한다.
  1. CMK
    • 256-bit AES 키이며, 이 키는 내보낼 수 없다.
    • 키에 사용되는 대칭 알고리즘은 AES-GCM-256을 사용한다.
    • CMK를 사용하여 최대 4KB의 데이터를 암호화하고 해제 할 수 있다.
  2. Data Key
    • CMK를 사용하여 생성한다.
    • 많은 양의 데이터를 암호화 하는데 사용한다.

GCP KMS(Google Cloud Platform Key Management Service)

  • 암호화 표준은 RSA-OAEP와 AES-GCM을 사용한다.
  • 암호화 Key의 정확한 제어 엑세스 관리를 위해 Key ring, Key, Key version이라는 계층 구조를 가지고 있다.
  1. Key ring
    • 조직화 목적을 위해 키를 그룹화 한 것 이다.
    • Key는 Key를 포함하는 Key ring에서 권한을 상속받는다. 연관된 권한을 가진 Key를 Key ring으로 그룹화하면 각 키를 개벽적으로 작업을 수행할 필요 없이 Key ring 수준에서 해당 키를 대상으로 권한을 부여, 취소, 수정 할 수 있다.
  2. Key
    • AES-256키를 GCM(Galois Counter Mode)로 사용한다.
    • 특정한 용도를 위해 사용되는 암호화 키를 나타내는 명명된 객체이다.
    • 시간이 경과 되어 새로운 키 버전이 생성되면 키자료인 암호화에 사용되는 실제 비트가 변경될 수 있음.
  3. Key version
    • 일정한 시점에 하나의 키와 관련된 키 자료를 나타낸다.
    • 임의의 여러 버전이 존재 할 수 있으며 버전은 최소 하나 이상 있어야 한다.

Azure Key Vault

  • 암호화 표준은 RSA-OAEP를 사용한다.
  • 비밀정보를 중앙 위치에 보관하고 보안 액세스, 권한 제어 및 액세스 로깅을 제공한다.
  • 비밀 정보를 접근하고 사용하려면 Key Vault에 인증 해야하며, Key Vault 인증은 AAD(Azure Active Directory)에서 인증 지원하는 ID(App Client ID)를 통해 인증 받을 수 있다.
    • 접근 정책은 ‘작업’을 기반으로 한다.
      – Application 별로 비밀 값 읽기, 비밀 이름 나열, 비밀 만들기 등의 권한을 부여한다.
  • 제공되는 보안 컨트롤
    • Data Protect
      – TDE(투명한 데이터 암호화)와 Azure Key Vault를 통합하면 TDE 보호기라는 고객 관리형 비대칭 키를 사용하여 DEK(데이터베이스 암호화 키)를 암호화할 수 있습니다.
    • Network ACL
      – 가상 네트워크 서비스 End-Point를 사용하면 지정된 가상 네트워크에 대한 액세스를 제한할 수 있습니다.

정리하면, AWS, GCP의 KMS는 암호화 키를 안전하게 저장 하는 것과 키를 암호화하는 작업(암호화와 복호화)에  초점이 맞춰져 있다고 볼 수 있고, 반면, Azure Key Vault는 백엔드에서는 키 암호화 작업을 통해 비밀을 저장하는 등, KMS와 유사하게 기능들을 제공하지만 그 외 추가 적인 관리 기능들을 제공하기 때문에 비밀 관리 솔루션을 제공한다고 볼 수 있다.