Amazon CloudFront
개발자 안내서 (API 버전 2016-09-29)

필드 레벨 암호화 사용으로 민감한 데이터 보호

이미 CloudFront를 구성하여 HTTPS를 사용한 오리진 서버로의 보안 종단 간 연결 적용을 지원할 수 있습니다. 필드 레벨 암호화는 HTTPS와 함께 추가 보안 레이어를 추가하여 시스템 처리 전체에서 특정 데이터를 보호하고 특정 애플리케이션만 이를 볼 수 있도록 합니다.

필드 레벨 암호화를 통해 사용자가 제출한 민감한 정보를 웹 서버에 안전하게 업로드할 수 있습니다. 클라이언트가 제공한 민감한 정보는 사용자에게 더욱 가까운 엣지에서 암호화되고, 전체 애플리케이션 스택에서 암호화를 유지하여 데이터를 필요로 하고 이를 해독할 자격 증명을 보유한 애플리케이션만이 이를 가능하도록 할 수 있습니다.

필드 레벨 암호화를 사용하려면 CloudFront 배포를 구성하여 암호화되기를 원하는 POST 요청의 필드 세트와 암호화에 사용할 퍼블릭 키를 지정할 수 있습니다. 한 요청에서 최대 10개의 데이터 필드를 암호화할 수 있습니다. (필드 레벨 암호화된 요청의 모든 데이터를 암호화할 수는 없습니다. 암호화할 개별 필드를 지정해야 합니다.)

필드 레벨 암호화가 포함된 HTTPS 요청이 오리진에 전달될 때 요청은 오리진 하위 시스템 전체에 라우팅되고, 민감한 데이터는 계속 암호화되어 민감한 데이터의 침해 또는 우발적 데이터 손실의 위험을 줄입니다. 크레딧 번호에 대한 액세스를 필요로 하는 결제 처리 시스템과 같이 업무상 사유에 따라 민감한 데이터에 대한 액세스를 필요로 하는 구성 요소는 적절한 프라이빗 키를 사용하여 해독하고 데이터에 액세스할 수 있습니다.

필드 레벨 암호화를 사용하려면 오리진이 chunked 인코딩을 지원해야 합니다.


				CloudFront에서 필드 레벨 암호화

CloudFront 필드 레벨 암호화는 퍼블릭 키 암호화라고도 하는 비대칭 암호화를 사용합니다. CloudFront에 퍼블릭 키를 입력하면 지정한 모든 민감한 데이터가 자동적으로 암호화됩니다. CloudFront에 입력한 키는 암호화된 값의 해독에 사용할 수 없습니다. 이는 프라이빗 키만이 가능합니다.


				민감한 데이터만 암호화

필드 레벨 암호화 개요

다음 단계는 필드 레벨 암호화 설정의 개요를 제공합니다. 자세한 단계는 필드 레벨 암호화 설정 단원을 참조하십시오.

  1. 퍼블릭 키-프라이빗 키 페어를 가져옵니다. CloudFront에서 필드 레벨 암호화를 설정하기 전에 퍼블릭 키를 얻고 이를 추가해야 합니다.

  2. 필드 레벨 암호화 프로필을 생성합니다. CloudFront에서 생성한 필드 레벨 암호화 프로필은 암호화하고자 하는 필드를 정의합니다.

  3. 필드 레벨 암호화 구성을 생성합니다. 구성은 요청의 콘텐츠 유형 또는 쿼리 인수를 기반으로 특정 데이터 필드 암호화에 사용할 프로필을 지정합니다. 각기 다른 시나리오에 대해 원하는 요청 전달 동작 옵션을 선택할 수도 있습니다. 예를 들어, 요청 URL의 쿼리 인수에 의해 프로필 이름이 지정될 때 이는 CloudFront.에 존재하지 않습니다.

  4. 캐시 동작에 연결합니다. 배포에 대한 캐시 동작의 구성을 연결하여 CloudFront가 데이터를 암호화할 시기를 지정합니다.

필드 레벨 암호화 설정

다음 단계를 따라 필드 레벨 암호화 사용을 시작합니다. 필드 레벨 암호화의 제한에 대한 자세한 내용은 한도 단원을 참조하십시오.

1단계: RSA 키 페어 생성

시작하려면 CloudFront가 데이터를 암호화할 수 있도록 퍼블릭 키를 포함하는 RSA 키 페어를 만들어야 합니다. 또한 오리진의 구성 요소가 암호화된 필드를 해독할 수 있도록 프라이빗 키를 만들어야 합니다. OpenSSL 또는 기타 도구를 사용해서 키 페어를 만들 수 있습니다. 키 크기는 2048비트여야 합니다.

예를 들어 OpenSSL을 사용하는 경우, 다음 명령으로 길이가 2048비트인 키 페어를 만들고 private_key.pem 파일에 저장할 수 있습니다.

openssl genrsa -out private_key.pem 2048

이렇게 만들어진 파일은 퍼블릭 키와 프라이빗 키를 모두 포함합니다. 그 파일에서 퍼블릭 키를 추출하려면 다음 명령을 실행합니다.

openssl rsa -pubout -in private_key.pem -out public_key.pem

퍼블릭 키 파일(public_key.pem)에는 다음 단계에서 붙여 넣는 암호화된 키 값이 포함됩니다.

2단계: CloudFront에 퍼블릭 키 추가

RSA 키 페어를 얻은 후 퍼블릭 키를 CloudFront에 추가합니다.

퍼블릭 키를 CloudFront에 추가하려면(콘솔)

  1. AWS Management 콘솔에 로그인한 다음 https://console.aws.amazon.com/cloudfront/에서 CloudFront 콘솔을 엽니다.

  2. 탐색 창에서 퍼블릭 키를 선택합니다.

  3. Add public key(퍼블릭 키 추가)를 선택합니다.

  4. 키 이름에 키의 고유 이름을 입력합니다. 이름은 공백을 포함할 수 없으며, 영숫자 문자, 밑줄(_) 및 하이픈(-)만 포함할 수 있습니다. 문자는 최대 128자입니다.

  5. 키 값에서 " -----BEGIN PUBLIC KEY-----" 및 "-----END PUBLIC KEY-----" 행을 포함한 퍼블릭 키의 암호화된 키 값을 붙여 넣습니다.

  6. 설명에 코멘트를 추가합니다(선택 사항). 예를 들어, 퍼블릭 키의 만료 날짜를 포함할 수 있습니다.

  7. 추가를 선택합니다.

이 절차의 단계를 반복하여 CloudFront에서 사용할 키를 더 추가할 수 있습니다.

3단계: 필드 레벨 암호화 프로필 생성

CloudFront에 하나 이상의 퍼블릭 키를 추가한 이후 CloudFront에 어떤 필드를 암호화할지 알리는 프로필을 생성합니다.

필드 레벨 암호화 프로필을 생성하려면(콘솔)

  1. 왼쪽 탐색 창에서 Field-level encryption(필드 레벨 암호화)을 선택합니다.

  2. Create profile(프로파일 생성)을 선택합니다.

  3. 다음 필드를 입력합니다.

    프로필 이름

    프로필의 고유한 이름을 입력합니다. 이름은 공백을 포함할 수 없으며, 영숫자 문자, 밑줄(_) 및 하이픈(-)만 포함할 수 있습니다. 문자는 최대 128자입니다.

    퍼블릭 키 이름

    2단계에서 CloudFront에 추가한 퍼블릭 키의 이름을 드롭다운 목록에서 선택합니다. CloudFront는 키를 사용하여 이 프로필에서 지정한 필드를 암호화합니다.

    공급자 이름

    키 페어를 얻은 공급자와 같이 키를 식별하는 데 도움이 될 구문을 입력합니다. 프라이빗 키와 함께 이 정보는 애플리케이션이 데이터 필드를 해독할 때 필요합니다. 공급자 이름은 공백을 포함할 수 없으며, 영숫자 문자, 콜론(:), 밑줄(_) 및 하이픈(-)만 포함할 수 있습니다. 문자는 최대 128자입니다.

    일치시킬 필드 이름 패턴

    CloudFront에서 암호화하고자 하는 데이터 필드의 이름 또는 요청에서 데이터 필드 이름을 식별하는 패턴을 입력합니다. + 옵션을 사용하여 이 키를 사용하여 암호화하고자 하는 모든 필드를 추가합니다.

    필드 이름 패턴의 경우 데이터 필드의 전체 이름(예: DateOfBirth)을 입력하거나 와일드카드 문자(*)를 포함하여 이름의 첫 부분(예: CreditCard*)만을 입력할 수 있습니다. 필드 이름 패턴은 영숫자 문자, 대괄호([ 및 ]), 마침표(.), 밑줄(_) 및 하이픈(-)만을 포함할 수 있으며, 추가로 와일드카드 문자(*)를 선택적으로 포함할 수 있습니다.

    다른 필드 이름 패턴과 중첩되는 문자를 사용하지 마세요. 예를 들어, ABC*라는 필드 이름 패턴을 보유한 경우 또 다른 AB* 필드 이름 패턴을 추가할 수는 없습니다. 추가로 필드 이름은 대소문자를 구분하며, 사용할 수 있는 최대 문자는 128자입니다.

    Comment

    (선택 사항) 이 프로필에 대한 설명을 입력합니다. 사용할 수 있는 최대 문자 수는 128자입니다.

  4. 필드에 내용을 입력한 후 Create profile(프로파일 생성)을 선택합니다.

  5. 프로필을 더 추가하고자 하는 경우 프로필 추가를 선택합니다.

4단계: 구성 생성

하나 이상의 필드 레벨 암호화 프로필을 생성한 이후, 암호화할 데이터를 포함하는 요청의 콘텐츠 유형, 암호화에 사용할 프로필, CloudFront의 암호화 처리 방법을 지정하는 기타 옵션을 지정하는 구성을 생성합니다.

예를 들어, CloudFront가 데이터를 암호화할 수 없을 때 다음 시나리오에서 CloudFront가 요청을 차단하거나 오리진으로 전달할지 여부를 지정할 수 있습니다.

  • 요청의 콘텐츠 유형이 구성에 없을 때. 구성에 콘텐츠 유형을 추가하지 않은 경우 CloudFront가 해당 콘텐츠 유형을 포함한 요청을 데이터 필드 암호화 없이 오리진에 전달할지 또는 요청을 차단하고 오류를 반환할지 여부를 지정할 수 있습니다.

    참고: 구성에 콘텐츠 유형을 추가했지만 해당 유형을 사용할 프로필을 지정하지 않은 경우 해당 콘텐츠 유형을 포함한 요청은 항상 오리진으로 전달됩니다.

  • 쿼리 인수에 입력된 프로필 이름이 알 수 없는 이름임. 배포에 존재하지 않는 프로필 이름을 포함하는 fle-profile 쿼리 인수를 지정할 때 CloudFront가 요청을 데이터 필드 암호화 없이 오리진으로 보낼지 또는 요청을 차단하고 오류를 반환할지 여부를 지정할 수 있습니다.

구성에서 URL에 쿼리 인수로 프로필을 입력함으로써 해당 쿼리에 대한 콘텐츠 유형으로 매핑한 프로필을 무시할지 여부를 지정할 수도 있습니다. 기본적으로 CloudFront는 콘텐츠 유형에 매핑한 프로필을 사용합니다(이를 지정한 경우). 이를 통해 기본적으로 사용할 프로필을 가질 수 있지만 다른 프로필을 적용하고자 하는 특정 요청을 정할 수도 있습니다.

예를 들어, 사용할 쿼리 인수로 (구성에 있는) SampleProfile을 지정할 수 있습니다. 그런 다음, https://d1234.cloudfront.net 대신 URL https://d1234.cloudfront.net?fle-profile=SampleProfile을 사용하여 CloudFront가 요청의 콘텐츠 유형에 대해 설정한 프로필 대신 이 요청에서 SampleProfile을 사용하도록 할 수 있습니다.

단일 계정에 대해 최대 10개의 구성을 생성할 수 있으며 계정에 대한 모든 배포의 캐시 동작에 구성 중 하나를 연결할 수 있습니다.

필드 레벨 암호화 구성을 생성하려면(콘솔)

  1. Field-level encryption(필드 레벨 암호화) 페이지에서 구성 만들기를 선택합니다.

    참고: 최소 하나의 프로필을 생성하지 않은 경우 구성 생성 옵션이 표시되지 않습니다.

  2. 다음 필드를 입력하여 사용할 프로필을 지정합니다. (일부 필드는 변경할 수 없습니다.)

    콘텐츠 유형(변경할 수 없음)

    콘텐츠 유형은 application/x-www-form-urlencoded로 설정되며 변경할 수 없습니다.

    기본 프로필 ID(선택 사항)

    드롭다운 목록 가운데 콘텐츠 유형 필드에서 콘텐츠 유형을 매핑하고자 하는 프로필을 선택합니다.

    콘텐츠 형식(변경할 수 없음)

    콘텐츠 형식은 URLencoded로 설정되며 변경할 수 없습니다.

  3. 다음 옵션에 대한 CloudFront 기본 동작을 변경하고자 하는 경우 해당 확인란을 선택합니다.

    요청의 콘텐츠 유형이 구성되지 않을 때 오리진으로 요청 전달

    요청의 콘텐츠 유형에 대해 사용할 프로필을 지정하지 않았다면 요청이 오리진으로 이동하도록 허용할 경우 확인란을 선택합니다.

    입력된 쿼리 인수를 포함한 콘텐츠 유형에 대한 프로필 무시

    쿼리 인수에 입력된 프로필이 콘텐츠 유형에 대해 지정한 프로필을 무시하도록 허용할 경우 확인란을 선택합니다.

  4. 확인란을 선택하여 쿼리 인수가 기본 프로필을 무시하도록 허용할 경우 구성에 대한 다음 추가 필드를 입력해야 합니다. 쿼리에 사용할 쿼리 인수 매핑 가운데 최대 5개를 생성할 수 있습니다.

    쿼리 인수

    fle-profile 쿼리 인수에 대해 URL에서 포함하고자 하는 값을 입력합니다. 이 값은 CloudFront에 이 쿼리의 필드 레벨 암호화에 대한 쿼리 인수와 연결된 프로필 ID(다음 필드에서 지정)를 사용하도록 합니다.

    사용할 수 있는 최대 문자 수는 128자입니다. 값에는 공백이 포함될 수 없으며, 영숫자 문자와 다음 문자만을 사용할 수 있습니다. 대시(-), 마침표(.), 밑줄(_), 별표(*) 더하기 기호(+), 퍼센트(%).

    프로필 ID

    드롭다운 목록 가운데 쿼리 인수에 입력한 값과 연결하고자 하는 프로필을 선택합니다.

    쿼리 인수에 지정된 프로필이 존재하지 않을 때 요청을 오리진에 전달

    쿼리 인수에서 지정된 프로필이 CloudFront에서 정의되지 않은 경우 요청이 오리진으로 이동하도록 허용하려면 이 확인란을 선택합니다.

5단계: 캐시 동작에 구성 추가

필드 레벨 암호화를 사용하려면 배포에 대한 값으로 구성 ID를 추가함으로써 배포에 대한 캐시 동작과 구성을 연결합니다. 캐시 동작과 구성을 연결하려면 Viewer Protocol Policy와 Origin Protocol Policy는 HTTPS여야 합니다.

자세한 내용은 배포를 만들거나 업데이트할 때 지정하는 값 단원을 참조하십시오.

오리진의 데이터 필드 해독

CloudFront는 AWS 암호화 SDK를 사용하여 데이터 필드를 암호화합니다. 데이터는 애플리케이션 스택에 걸쳐 암호화를 유지하며, 이를 해독할 자격 증명을 보유한 애플리케이션만이 액세스할 수 있습니다.

암호화 이후 암호 텍스트는 base64 암호화됩니다. 애플리케이션이 오리진의 텍스트를 해독할 때 우선 암호 텍스트를 디코딩한 다음 AWS 암호화 SDK를 사용하여 데이터를 해독해야 합니다.

다음 코드 샘플은 애플리케이션이 오리진의 데이터를 해독하는 방법을 보여줍니다. 다음을 참조하십시오.

  • 예제를 간소화하기 위해 이 샘플은 작업 디렉터리에 있는 파일에서 퍼블릭 및 프라이빗 키(DER 형식)를 로드합니다. 실제로는 프라이빗 키를 오프라인 하드웨어 보안 모듈과 같은 안전한 오프라인 위치에 저장하고, 퍼블릭 키를 개발 팀에 배포합니다.

  • CloudFront는 데이터를 암호화하는 동안 특정 정보를 사용하며 동일한 파라미터 세트를 오리진에서 사용하여 이를 해독해야 합니다. MasterKey를 초기화하는 동안 CloudFront가 사용하는 파라미터는 다음을 포함합니다.

    • PROVIDER_NAME: 필드 레벨 암호화 프로필을 생성할 때 이 값을 지정했습니다. 여기에서 동일한 값을 사용합니다.

    • KEY_NAME: 퍼블릭 키를 CloudFront로 업로드할 때 퍼블릭 키의 이름을 생성했으며, 프로필에서 키 이름을 지정했습니다. 여기에서 동일한 값을 사용합니다.

    • ALGORITHM: CloudFront는 "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"을 암호화 알고리즘으로 사용합니다. 따라서 동일한 알고리즘을 사용하여 데이터를 해독해야 합니다.

  • 입력으로 암호 텍스트를 포함한 다음 샘플 프로그램을 실행하는 경우 암호화된 데이터가 콘솔에 출력됩니다. 자세한 내용은 AWS 암호화 SDK의 Java 예제 코드 단원을 참조하십시오.

샘플 코드

import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import org.apache.commons.codec.binary.Base64; import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoResult; import com.amazonaws.encryptionsdk.jce.JceMasterKey; /** * Sample example of decrypting data that has been encrypted by CloudFront Field-Level Encryption. */ public class DecryptExample { private static final String PRIVATE_KEY_FILENAME = "private_key.der"; private static final String PUBLIC_KEY_FILENAME = "public_key.der"; private static PublicKey publicKey; private static PrivateKey privateKey; // CloudFront uses the following values to encrypt data, and your origin must use same values to decrypt it. // In your own code, for PROVIDER_NAME, use the provider name that you specified when you created your Field Level // Encryption Profile. This sample uses 'DEMO' for the value. private static final String PROVIDER_NAME = "DEMO"; // In your own code, use the Key name that you specified when you added your public key to CloudFront. This sample // uses 'DEMOKEY' for the Key name. private static final String KEY_NAME = "DEMOKEY"; // Cloudfront uses this algorithm when encrypting data. private static final String ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; public static void main(final String[] args) throws Exception { final String dataToDecrypt = args[0]; // This sample uses files to get public and private keys. // In practice, you should distribute the public key and save the private key in secure storage. populateKeyPair(); System.out.println(decrypt(debase64(dataToDecrypt))); } private static String decrypt(final byte[] bytesToDecrypt) throws Exception { // You can decrypt the stream only by using the private key. // 1. Instantiate the SDK final AwsCrypto crypto = new AwsCrypto(); // 2. Instantiate a JCE master key final JceMasterKey masterKey = JceMasterKey.getInstance( publicKey, privateKey, PROVIDER_NAME, KEY_NAME, ALGORITHM); // 3. Decrypt the data final CryptoResult <byte[], ? > result = crypto.decryptData(masterKey, bytesToDecrypt); return new String(result.getResult()); } // Function to decode base64 cipher text. private static byte[] debase64(final String value) { return Base64.decodeBase64(value.getBytes()); } private static void populateKeyPair() throws Exception { final byte[] PublicKeyBytes = Files.readAllBytes(Paths.get(PUBLIC_KEY_FILENAME)); final byte[] privateKeyBytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILENAME)); publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(PublicKeyBytes)); privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); } }