본문 바로가기
개발/Azure

[AZURE] DB 암호화4 SSMS에서 CMK/CEK 생성 + 열 암호화

by HW프로젝트 2025. 12. 18.

4단계로 SSMS에서 열암호화를 진행한다.

 

 

암호화할 열 선택 > 암호화 유형: 결정적 (Deterministic) > 암호화 키: CEK_Auto1 (새 열) 또는 자동 생성된 이름 > 다음 클릭

 

Azure에 로그인하려 했으나 조직메일이 아닌 개인메일로 가입해서 안되는것 같다.

 

⚠️ SSMS의 Always Encrypted 마법사는 "조직 계정"(회사/학교) 필요
⚠️ Gmail 같은 개인 Microsoft 계정은 지원 안 됨
✅ 해결책: Java 애플리케이션에서 서비스 주체로 설정

 

 

다시 Azure Portal로 이동해서 Key Vault 에서 키를 생성한다.

 

+ 생성/가져오기를 클릭하고 아래와 같이 진행한다.

 

그 다음 생성된 키 클릭해서 키 식별자 URL 복사한다.

 

자바로 CEK/CMK 키 생성을 구현한다.

package com.example.encrypt;

import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionAzureKeyVaultProvider;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerConnection;

import java.security.SecureRandom;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;

/**
 * Always Encrypted - CMK/CEK 생성 스크립트
 * Azure Key Vault를 사용하여 Column Master Key와 Column Encryption Key를 생성합니다.
 */
public class AlwaysEncryptedSetup {

    // Azure AD 앱 설정
    private static final String CLIENT_ID = "your-client-id";
    private static final String CLIENT_SECRET = "your-client-secret";
    private static final String TENANT_ID = "your-tenant-id";
    
    // Azure Key Vault 설정
    private static final String KEY_VAULT_URL = "https://your-keyvault.vault.azure.net/";
    private static final String KEY_NAME = "CMK-Name";  // Key Vault에 생성한 키 이름

    // SQL Server 설정
    private static final String DB_URL = "jdbc:sqlserver://your-server:1433;databaseName=YourDB;encrypt=true;trustServerCertificate=true";
    private static final String DB_USER = "sa";
    private static final String DB_PASSWORD = "password";

    // CMK/CEK 이름 (SQL Server에 등록될 이름)
    private static final String CMK_NAME = "CMK_AzureKeyVault";
    private static final String CEK_NAME = "CEK_AzureKeyVault";

    public static void main(String[] args) {
        try {
            System.out.println("=== Always Encrypted 설정 시작 ===\n");

            // 1. Azure Key Vault Provider 등록
            System.out.println("[1/3] Azure Key Vault Provider 등록...");
            registerProvider();
            System.out.println("      완료\n");

            // 2. Column Master Key 생성
            System.out.println("[2/3] Column Master Key 생성...");
            createCMK();
            System.out.println("      완료\n");

            // 3. Column Encryption Key 생성
            System.out.println("[3/3] Column Encryption Key 생성...");
            createCEK();
            System.out.println("      완료\n");

            System.out.println("=== CMK/CEK 생성 완료! ===");

        } catch (Exception e) {
            System.err.println("오류: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * Azure Key Vault Provider 등록
     */
    private static void registerProvider() throws Exception {
        ClientSecretCredential credential = new ClientSecretCredentialBuilder()
                .clientId(CLIENT_ID)
                .clientSecret(CLIENT_SECRET)
                .tenantId(TENANT_ID)
                .build();

        SQLServerColumnEncryptionAzureKeyVaultProvider provider =
                new SQLServerColumnEncryptionAzureKeyVaultProvider(credential);

        Map<String, SQLServerColumnEncryptionKeyStoreProvider> providers = new HashMap<>();
        providers.put("AZURE_KEY_VAULT", provider);
        SQLServerConnection.registerColumnEncryptionKeyStoreProviders(providers);
    }

    /**
     * Column Master Key 생성
     * - Key Vault의 키를 참조하는 CMK를 SQL Server에 등록
     */
    private static void createCMK() throws SQLException {
        String keyPath = KEY_VAULT_URL + "keys/" + KEY_NAME;

        String sql = "CREATE COLUMN MASTER KEY [" + CMK_NAME + "] " +
                     "WITH (KEY_STORE_PROVIDER_NAME = 'AZURE_KEY_VAULT', " +
                     "KEY_PATH = '" + keyPath + "')";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
            System.out.println("      CMK: " + CMK_NAME);
            System.out.println("      Key Path: " + keyPath);
        }
    }

    /**
     * Column Encryption Key 생성
     * - CEK를 생성하고 CMK(Azure Key Vault)로 암호화하여 SQL Server에 등록
     */
    private static void createCEK() throws Exception {
        // 32바이트(256비트) 랜덤 CEK 생성
        byte[] cekPlaintext = new byte[32];
        new SecureRandom().nextBytes(cekPlaintext);

        // Azure Key Vault Provider로 CEK 암호화
        ClientSecretCredential credential = new ClientSecretCredentialBuilder()
                .clientId(CLIENT_ID)
                .clientSecret(CLIENT_SECRET)
                .tenantId(TENANT_ID)
                .build();

        SQLServerColumnEncryptionAzureKeyVaultProvider provider =
                new SQLServerColumnEncryptionAzureKeyVaultProvider(credential);

        String keyPath = KEY_VAULT_URL + "keys/" + KEY_NAME;
        byte[] encryptedCek = provider.encryptColumnEncryptionKey(keyPath, "RSA_OAEP", cekPlaintext);

        // SQL Server에 CEK 등록
        String sql = "CREATE COLUMN ENCRYPTION KEY [" + CEK_NAME + "] " +
                     "WITH VALUES (COLUMN_MASTER_KEY = [" + CMK_NAME + "], " +
                     "ALGORITHM = 'RSA_OAEP', " +
                     "ENCRYPTED_VALUE = 0x" + bytesToHex(encryptedCek) + ")";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
            System.out.println("      CEK: " + CEK_NAME);
        }
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }
}

 

 

사용한 Maven은 아래와 같다.

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>12.8.1.jre8</version>
</dependency>
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-identity</artifactId>
    <version>1.11.1</version>
</dependency>
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-security-keyvault-keys</artifactId>
    <version>4.7.1</version>
</dependency>

 

 

CMK/CEK 생성 완료되면 다시 열암호화를 진행한다.

 

다음을 눌러서 암호화를 진행한다.

 

아래와 같이 나오면 열암호화가 완료된다.