Azure Key Vault 인증서를 사용하여 Spring Boot에서 HTTPS 사용

이 자습서에서는 Azure Key Vault 및 Azure 리소스에 대한 관리 ID를 사용하여 TLS/SSL 인증서로 Spring Boot(Azure Spring Apps 포함) 앱을 보호하는 방법을 보여 줍니다.

클라우드 또는 온-프레미스에서 프로덕션 등급 Spring Boot 애플리케이션은 표준 TLS 프로토콜을 사용하는 네트워크 트래픽에 대한 엔드투엔드 암호화가 필요합니다. 대부분의 TLS/SSL 인증서는 공용 루트 CA(인증 기관)에서 검색할 수 있습니다. 그러나 이 검색을 수행할 수 없는 경우도 있습니다. 인증서를 검색할 수 없는 경우 앱은 이러한 인증서를 로드하고, 인바운드 네트워크 연결에 표시하고, 아웃바운드 네트워크 연결에서 수락할 수 있는 방법이 있어야 합니다.

Spring Boot 앱은 일반적으로 인증서를 설치하여 TLS를 사용하도록 설정합니다. 인증서는 Spring Boot 앱을 실행하는 JVM의 로컬 키 저장소에 설치됩니다. Spring on Azure에서는 인증서가 로컬로 설치되지 않습니다. 대신 Microsoft Azure에 대한 Spring 통합은 Azure Key Vault 및 Azure 리소스에 대한 관리 ID의 도움을 받아 TLS를 사용하도록 설정하는 안전하고 마찰 없는 방법을 제공합니다.

Diagram showing interaction of elements in this tutorial.

Important

현재 Spring Cloud Azure Certificate Starter 버전 4.x 이상은 TLS/mTLS를 지원하지 않으며 Key Vault 인증서 클라이언트만 자동으로 구성합니다. 따라서 TLS/mTLS를 사용하려는 경우 버전 4.x로 마이그레이션할 수 없습니다.

필수 조건

Important

이 문서의 단계를 완료하려면 Spring Boot 버전 2.5 이상이 필요합니다.

자체 서명된 TLS/SSL 인증서 설정

이 자습서의 단계는 Azure Key Vault에 직접 저장된 TLS/SSL 인증서(자체 서명 포함)에 적용됩니다. 자체 서명된 인증서는 프로덕션 환경에서 사용하기에는 적합하지 않지만 개발 및 테스트 애플리케이션에 유용합니다.

이 자습서에서는 자체 서명된 인증서를 사용합니다. 인증서를 설정하려면 빠른 시작: Azure Portal을 사용하여 Azure Key Vault에서 인증서 설정 및 검색을 참조하세요.

참고 항목

인증서를 설정한 후 Key Vault 액세스 정책 할당의 지침에 따라 VM에 Key Vault에 대한 액세스 권한을 부여합니다.

TLS/SSL 인증서를 통한 보안 연결

이제 VM 및 Key Vault 인스턴스가 있으며 Key Vault에 대한 VM 액세스 권한을 부여했습니다. 다음 섹션에서는 Spring Boot 애플리케이션의 Azure Key Vault에서 TLS/SSL 인증서를 통해 안전하게 연결하는 방법을 보여 줍니다. 이 자습서에서는 다음 두 가지 시나리오를 보여 줍니다.

  • 보안 인바운드 연결을 사용하여 Spring Boot 애플리케이션 실행
  • 보안 아웃바운드 연결을 사용하여 Spring Boot 애플리케이션 실행

다음 단계에서 코드는 실행 파일로 패키지되고 VM에 업로드됩니다. VM에 OpenJDK를 설치하는 것을 잊지 마세요.

보안 인바운드 연결을 사용하여 Spring Boot 애플리케이션 실행

인바운드 연결에 대한 TLS/SSL 인증서가 Azure Key Vault에서 제공되는 경우 다음 단계에 따라 애플리케이션을 구성합니다.

  1. pom.xml 파일에 다음 종속성을 추가합니다.

    <dependency>
       <groupId>com.azure.spring</groupId>
       <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId>
       <version>3.14.0</version>
    </dependency>
    
  2. application.properties 구성 파일에서 Key Vault 자격 증명을 구성합니다.

    server.ssl.key-alias=<the name of the certificate in Azure Key Vault to use>
    server.ssl.key-store-type=AzureKeyVault
    server.ssl.trust-store-type=AzureKeyVault
    server.port=8443
    azure.keyvault.uri=<the URI of the Azure Key Vault to use>
    

    이러한 값을 사용하면 Spring Boot 앱이 자습서의 시작 부분에 멘션 대로 TLS/SSL 인증서에 대한 로드 작업을 수행할 수 있습니다. 다음 표에서는 속성 값에 대해 설명합니다.

    속성 설명
    server.ssl.key-alias 에 전달한 --name 인수의 값입니다 az keyvault certificate create.
    server.ssl.key-store-type AzureKeyVault이어야 합니다.
    server.ssl.trust-store-type AzureKeyVault이어야 합니다.
    server.port HTTPS 연결을 수신 대기할 로컬 TCP 포트입니다.
    azure.keyvault.uri vaultUri 반환 JSONaz keyvault create의 속성입니다. 이 값을 환경 변수에 저장했습니다.

    Key Vault와 관련된 유일한 속성은 .입니다 azure.keyvault.uri. 앱이 시스템 할당 관리 ID에 Key Vault에 대한 액세스 권한이 부여된 VM에서 실행되고 있습니다. 따라서 앱에 액세스 권한도 부여되었습니다.

    이러한 변경 내용을 통해 Spring Boot 앱은 TLS/SSL 인증서를 로드할 수 있습니다. 다음 단계에서는 자습서의 시작 부분에서 멘션 대로 앱이 TLS/SSL 인증서에 대한 수락 작업을 수행할 수 있도록 설정합니다.

  3. 다음 내용이 포함되도록 시작 클래스 파일을 편집합니다.

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    public class SsltestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SsltestApplication.class, args);
        }
    
        @GetMapping(value = "/ssl-test")
        public String inbound(){
            return "Inbound TLS is working!!";
        }
    
        @GetMapping(value = "/exit")
        public void exit() {
            System.exit(0);
        }
    
    }
    

    System.exit(0) 인증되지 않은 REST GET 호출 내에서 호출하는 것은 데모용입니다. 실제 애플리케이션에서는 사용하지 System.exit(0) 마세요.

    이 코드는 이 자습서의 시작 부분에 멘션 현재 동작을 보여 줍니다. 다음 목록에서는 이 코드에 대한 몇 가지 세부 정보를 강조 표시합니다.

    • 이제 @RestController Spring Initializr에서 생성한 클래스에 SsltestApplication 대한 주석이 있습니다.
    • 호출한 HTTP용으로 주석이 추가된 @GetMappingvalue 메서드가 있습니다.
    • inbound 메서드는 브라우저에서 /ssl-test 경로에 대한 HTTPS 요청을 만들 때 인사말을 반환하는 간단한 일을 합니다 . inbound 메서드는 서버에서 TLS/SSL 인증서를 브라우저에 제공하는 방법을 보여줍니다.
    • exit 메서드를 사용하면 JVM이 호출될 때 종료됩니다. 이 메서드를 사용하면 자습서의 컨텍스트에서 샘플을 쉽게 실행할 수 있습니다.
  4. 다음 명령을 실행하여 코드를 컴파일하고 실행 가능한 JAR 파일로 패키지합니다.

    mvn clean package
    
  5. <your-resource-group-name> 내에 만든 네트워크 보안 그룹이 IP 주소의 포트 22 및 8443에서 인바운드 트래픽을 허용하는지 확인합니다. 인바운드 트래픽을 허용하도록 네트워크 보안 그룹 규칙을 구성하는 방법에 대한 자세한 내용은 네트워크 보안 그룹 만들기, 변경 또는 삭제의 보안 규칙 작업 섹션을 참조하세요.

  6. VM에 실행 파일 JAR 파일을 배치합니다.

    cd target
    sftp azureuser@<your VM public IP address>
    put *.jar
    

    Spring Boot 앱을 빌드하고 VM에 업로드했으므로 다음 단계를 사용하여 VM에서 실행하고 REST 엔드포인트를 curl호출합니다.

  7. SSH를 사용하여 VM에 연결한 다음 실행 파일 JAR을 실행합니다.

    set -o noglob
    ssh azureuser@<your VM public IP address> "java -jar *.jar"
    
  8. 새 Bash 셸을 열고 다음 명령을 실행하여 서버가 TLS/SSL 인증서를 제공하는지 확인합니다.

    curl --insecure https://<your VM public IP address>:8443/ssl-test
    
  9. exit 경로를 호출하여 서버를 중지하고 네트워크 소켓을 닫습니다.

    curl --insecure https://<your VM public IP address>:8443/exit
    

이제 부하 확인하고 자체 서명된 TLS/SSL 인증서를 사용하여 작업을 표시했으므로 앱에 대한 몇 가지 사소한 변경을 수행하여 수락 작업도 확인합니다.

보안 아웃바운드 연결을 사용하여 Spring Boot 애플리케이션 실행

이 섹션에서는 아웃바운드 연결에 대한 TLS/SSL 인증서가 Azure Key Vault에서 제공되도록 이전 섹션의 코드를 수정합니다. 따라서 로드, 제공허용 작업은 Azure Key Vault에서 충족됩니다.

  1. pom.xml 파일에 Apache HTTP 클라이언트 종속성을 추가합니다.

    <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
       <version>4.5.13</version>
    </dependency>
    
  2. 라는 ssl-test-outbound새 rest 엔드포인트를 추가합니다. 이 엔드포인트는 자체에 대한 TLS 소켓을 열고 TLS 연결이 TLS/SSL 인증서를 허용하는지 확인합니다. 시작 클래스의 이전 부분을 다음 코드로 바꿉다.

    import java.security.KeyStore;
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import com.azure.security.keyvault.jca.KeyVaultLoadStoreParameter;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.SSLContexts;
    
    @SpringBootApplication
    @RestController
    public class SsltestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SsltestApplication.class, args);
        }
    
        @GetMapping(value = "/ssl-test")
        public String inbound(){
            return "Inbound TLS is working!!";
        }
    
        @GetMapping(value = "/ssl-test-outbound")
        public String outbound() throws Exception {
            KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
            KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
                System.getProperty("azure.keyvault.uri"));
            azureKeyVaultKeyStore.load(parameter);
            SSLContext sslContext = SSLContexts.custom()
                                               .loadTrustMaterial(azureKeyVaultKeyStore, null)
                                               .build();
    
            HostnameVerifier allowAll = (String hostName, SSLSession session) -> true;
            SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, allowAll);
    
            CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();
    
            HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();
    
            requestFactory.setHttpClient(httpClient);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            String sslTest = "https://localhost:8443/ssl-test";
    
            ResponseEntity<String> response
                = restTemplate.getForEntity(sslTest, String.class);
    
            return "Outbound TLS " +
                (response.getStatusCode() == HttpStatus.OK ? "is" : "is not")  + " Working!!";
        }
    
        @GetMapping(value = "/exit")
        public void exit() {
            System.exit(0);
        }
    
    }
    
  3. 다음 명령을 실행하여 코드를 컴파일하고 실행 가능한 JAR 파일로 패키지합니다.

    mvn clean package
    
  4. 이 문서의 앞부분에서 사용한 sftp 명령을 똑같이 사용하여 앱을 다시 업로드합니다.

    cd target
    sftp <your VM public IP address>
    put *.jar
    
  5. VM에서 앱을 실행합니다.

    set -o noglob
    ssh azureuser@<your VM public IP address> "java -jar *.jar"
    
  6. 서버가 실행된 후 서버가 TLS/SSL 인증서를 허용하는지 확인합니다. 이전 curl 명령을 실행한 동일한 Bash 셸에서 다음 명령을 실행합니다.

    curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
    

    메시지가 Outbound TLS is working!!표시됩니다.

  7. exit 경로를 호출하여 서버를 중지하고 네트워크 소켓을 닫습니다.

    curl --insecure https://<your VM public IP address>:8443/exit
    

Azure Key Vault에 저장된 자체 서명된 TLS/SSL 인증서를 사용하는 로드, 제공허용 작업을 간단하게 살펴보았습니다.

Azure Spring Apps에 배포

이제 Spring Boot 애플리케이션을 로컬로 실행했으므로 이제 프로덕션으로 이동해야 합니다. Azure Spring Apps 를 사용하면 코드를 변경하지 않고도 Spring Boot 애플리케이션을 Azure에 쉽게 배포할 수 있습니다. 이 서비스는 개발자가 코드에 집중할 수 있도록 Spring 애플리케이션의 인프라를 관리합니다. Azure Spring Apps는 포괄적인 모니터링 및 진단, 구성 관리, 서비스 검색, CI/CD 통합, 파란색-녹색 배포 등을 사용하여 수명 주기 관리를 제공합니다. Azure Spring Apps에 애플리케이션을 배포하려면 Azure Spring Apps에 첫 번째 애플리케이션 배포를 참조하세요.

다음 단계

Spring 및 Azure에 대해 자세히 알아보려면 Spring on Azure 설명서 센터를 계속 진행하세요.