TPM(신뢰할 수 있는 플랫폼 모듈)이 있는 디바이스는 증명을 사용하여 부팅 무결성이 손상되지 않음을 증명하고 측정 부팅 프로세스를 사용하여 초기 부팅 기능 상태를 검색할 수 있습니다.
점점 더 많은 디바이스 유형, 부팅 로더 및 부팅 스택 공격을 수행하려면 그에 따라 진화하는 증명 솔루션이 필요합니다. 디바이스의 증명된 상태는 플랫폼 증명 증명의 내용을 확인하는 데 사용되는 증명 정책에 의해 구동됩니다.
이 문서에서는 TPM(신뢰할 수 있는 플랫폼 모듈) 증명 및 Azure Attestation에서 지원하는 기능에 대한 개요를 제공합니다.
개요
TPM 증명은 신뢰 당사자가 부팅 흐름의 유효성을 검사할 수 있는 지점까지 TPM 자체의 유효성을 검사하는 것부터 시작합니다.
일반적으로 TPM 키 증명 다음 기본 요소를 기반으로 합니다.
TPM 인증 유효성 검사
TPM의 유효성을 검사하여 TPM 신뢰성의 유효성을 검사합니다.
- 모든 TPM은 EK(인증 키)라는 고유한 비대칭 키와 함께 제공됩니다. 이 키는 제조업체에서 구울 수 있습니다. 이 키의 공용 부분을 EKPub라고 합니다. 연결된 프라이빗 키를 EKPriv라고 합니다. 일부 TPM 칩에는 또한는 EKPub에 대 한 제조업체에서 발급 된 EK 인증서가 있으며 이 인증서를 EKCert라고 합니다.
- CA(인증서 기관)는 EKPub 또는 EKCert 통해 TPM에 트러스트를 설정합니다.
- 디바이스는 인증서를 요청하는 키가 EKPub에 암호학적으로 바인딩되어 있고 TPM이 EKPriv를 소유하고 있음을 CA에 증명합니다.
- CA는 나타내는 키를 TPM으로 보호 증명 된 이제는 특별 한 발급 정책을 사용 하 여 인증서를 발급 합니다.
부팅 중에 수행된 측정값의 유효성을 검사합니다.
Azure Attestation 사용하여 부팅 중에 수행된 측정값의 유효성을 검사합니다.
- 신뢰할 수 있는 부팅 및 측정 부팅의 일부로 모든 단계의 유효성이 검사되고 TPM으로 측정됩니다. 다양한 플랫폼에 대해 서로 다른 이벤트가 측정됩니다. Windows의 측정 부팅 프로세스에 대한 자세한 내용은 Windows 부팅 프로세스 보안을 참조하세요.
- 부팅 시 증명 ID 키가 생성됩니다. EK 유효성 검사를 수행한 후 사용 중인 TPM이 인증서를 발급했다는 증명 서비스에 암호화 증명을 제공하는 데 사용됩니다.
- 신뢰 당사자는 부팅 프로세스 중에 수행된 측정값의 유효성을 검사하는 데 사용할 수 있는 Azure Attestation 대한 증명을 수행할 수 있습니다.
- 그런 다음 신뢰 당사자는 증명 문을 사용하여 리소스 또는 기타 작업에 대한 액세스를 제어할 수 있습니다.
개념적으로 TPM 증명은 이전 다이어그램과 같이 시각화할 수 있습니다. 신뢰 당사자는 플랫폼의 무결성 및 약속 위반을 확인하기 위해 Azure Attestation을 적용합니다. 확인 프로세스를 통해 워크로드를 실행하거나 리소스에 대한 액세스를 제공할 수 있습니다.
악성 부팅 공격으로부터 보호
성숙한 공격 기술은 부팅 체인을 감염하는 것을 목표로합니다. 부팅 공격은 공격자에게 시스템 리소스에 대한 액세스를 제공하고 공격자가 맬웨어 방지 소프트웨어에서 숨기도록 허용할 수 있습니다. 신뢰할 수 있는 부팅은 첫 번째 방어 순서로 작동합니다. 신뢰할 수 있는 부팅 및 증명을 사용하면 신뢰 당사자로 기능이 확장됩니다. 대부분의 공격자는 보안 부팅을 우회하거나 부팅 프로세스에서 원치 않는 이진 파일을 로드하려고 합니다.
원격 증명을 사용하면 신뢰 당사자가 약속 위반에 대해 전체 부팅 체인을 확인할 수 있습니다. 예를 들어 증명 서비스에 의한 보안 부팅 평가는 UEFI로 측정된 보안 변수 값의 유효성을 검사합니다.
측정된 부팅 계측은 암호화된 바인딩된 측정값을 만든 후에 변경할 수 없고 신뢰할 수 있는 구성 요소만 측정할 수 있도록 합니다. 이러한 이유로 보안 변수의 유효성을 검사하는 것으로는 사용을 보장하기에 충분합니다.
Azure Attestation은 중간자 공격으로부터 보호하기 위해 증명의 무결성이 유지되도록 보고서에 서명합니다.
간단한 정책을 사용할 수 있습니다.
version=1.0;
authorizationrules {
=> permit();
};
issuancerules
{
[type=="aikValidated", value==true] &&
[type=="secureBootEnabled", value==true] => issue(type="PlatformAttested", value=true);
};
부팅에서 하나의 구성 요소만 확인하는 것만으로는 충분하지 않은 경우가 있습니다. 코드 무결성 또는 HVCI(하이퍼바이저로 보호된 코드 무결성) 및 System Guard 보안 시작과 같은 보완 기능을 확인하면 디바이스의 보호 프로필이 추가됩니다. 또한 위반을 평가하고 플랫폼에 대한 확신을 가질 수 있도록 부팅에 피어링할 수 있는 기능이 필요합니다.
다음 예제에서는 정책 버전 1.2를 활용하여 보안 부팅, HVCI 및 System Guard 보안 시작에 대한 세부 정보를 확인합니다. 또한 부팅하는 동안 원치 않는(malicious.sys) 드라이버가 로드되지 않는지 확인합니다.
version=1.2;
authorizationrules {
=> permit();
};
issuancerules
{
// Verify if secure boot is enabled
c:[type == "events", issuer=="AttestationService"] => add(type = "efiConfigVariables", value = JmesPath(c.value, "Events[?EventTypeString == 'EV_EFI_VARIABLE_DRIVER_CONFIG' && ProcessedData.VariableGuid == '8BE4DF61-93CA-11D2-AA0D-00E098032B8C']"));
c:[type=="efiConfigVariables", issuer=="AttestationPolicy"]=> add(type = "secureBootEnabled", value = JsonToClaimValue(JmesPath(c.value, "[?ProcessedData.UnicodeName == 'SecureBoot'] | length(@) == `1` && @[0].ProcessedData.VariableData == 'AQ'")));
![type=="secureBootEnabled", issuer=="AttestationPolicy"] => add(type="secureBootEnabled", value=false);
// HVCI
c:[type=="events", issuer=="AttestationService"] => add(type="srtmDrtmEventPcr", value=JmesPath(c.value, "Events[? EventTypeString == 'EV_EVENT_TAG' && (PcrIndex == `12` || PcrIndex == `19`)].ProcessedData.EVENT_TRUSTBOUNDARY"));
c:[type=="srtmDrtmEventPcr", issuer=="AttestationPolicy"] => add(type="hvciEnabledSet", value=JsonToClaimValue(JmesPath(c.value, "[*].EVENT_VBS_HVCI_POLICY | @[?String == 'HypervisorEnforcedCodeIntegrityEnable'].Value")));
c:[type=="hvciEnabledSet", issuer=="AttestationPolicy"] => issue(type="hvciEnabled", value=ContainsOnlyValue(c.value, 1));
![type=="hvciEnabled", issuer=="AttestationPolicy"] => issue(type="hvciEnabled", value=false);
// Validating unwanted(malicious.sys) driver is not loaded
c:[type=="events", issuer=="AttestationService"] => add(type="boolProperties", value=JmesPath(c.value, "Events[? EventTypeString == 'EV_EVENT_TAG' && (PcrIndex == `12` || PcrIndex == `13` || PcrIndex == `19` || PcrIndex == `20`)].ProcessedData.EVENT_TRUSTBOUNDARY"));
c:[type=="boolProperties", issuer=="AttestationPolicy"] => issue(type="MaliciousDriverLoaded", value=JsonToClaimValue(JmesPath(c.value, "[*].EVENT_LOADEDMODULE_AGGREGATION[] | [? EVENT_IMAGEVALIDATED == true && (equals_ignore_case(EVENT_FILEPATH, '\\windows\\system32\\drivers\\malicious.sys') || equals_ignore_case(EVENT_FILEPATH, '\\windows\\system32\\drivers\\wd\\malicious.sys'))] | @ != null ")));
![type=="MaliciousDriverLoaded", issuer=="AttestationPolicy"] => issue(type="MaliciousDriverLoaded", value=false);
};
Linux에서 IMA(무결성 측정 아키텍처)를 통해 악성 부팅 공격으로부터 보호 확장
Linux 시스템은 Windows와 유사한 부팅 프로세스를 따르며, TPM 증명을 사용하면 보호 프로필을 커널로 부팅을 넘어 IMA(무결성 측정 아키텍처)로 확장할 수 있습니다. IMA 하위 시스템은 파일이 원격 및 로컬에서 실수로 또는 악의적으로 변경되었는지 감지하도록 설계되었으며, 런타임 측정 목록을 유지 관리하며 하드웨어 TPM(신뢰할 수 있는 플랫폼 모듈)에 고정된 경우 이 목록에 대한 집계 무결성 값은 소프트웨어 공격으로부터 복원력의 이점을 제공합니다. IMA 하위 시스템의 최근 향상된 기능을 통해 파일 기반 특성이 아닌 특성을 원격으로 측정하고 수집할 수도 있습니다. Azure 증명은 시스템 무결성에 대한 전체적인 보기를 제공하기 위해 원격으로 증명되는 파일 기반이 아닌 측정을 지원합니다.
다음 ima-policy를 사용하여 IMA를 사용하도록 설정하면 로컬 파일 무결성 증명을 사용하도록 설정하면서 비 파일 특성을 측정할 수 있습니다.
다음 증명 정책을 사용하여 이제 grub에서 전달한 secureboot, 커널 서명, 커널 버전, 커널 cmdline 및 IMA에서 지원하는 기타 주요 보안 특성의 유효성을 검사할 수 있습니다.
version = 1.2;
configurationrules
{
};
authorizationrules
{
[type == "aikValidated", value==true]
=> permit();
};
issuancerules {
// Retrieve all EFI Boot variables with event = 'EV_EFI_VARIABLE_BOOT'
c:[type == "events", issuer=="AttestationService"] => add(type ="efiBootVariables", value = JmesPath(c.value, "Events[?EventTypeString == 'EV_EFI_VARIABLE_BOOT']"));
// Retrieve all EFI Driver Config variables with event = 'EV_EFI_VARIABLE_DRIVER_CONFIG'
c:[type == "events", issuer=="AttestationService"] => add(type ="efiConfigVariables", value = JmesPath(c.value, "Events[?EventTypeString == 'EV_EFI_VARIABLE_DRIVER_CONFIG']"));
// Grab all IMA events
c:[type=="events", issuer=="AttestationService"] => add(type="imaMeasurementEvents", value=JmesPath(c.value, "Events[?EventTypeString == 'IMA_MEASUREMENT_EVENT']"));
// Look for "Boot Order" from EFI Boot Data
c:[type == "efiBootVariables", issuer=="AttestationPolicy"] => add(type = "bootOrderFound", value = JmesPath(c.value, "[?ProcessedData.UnicodeName == 'BootOrder'] | length(@) == `1` && @[0].PcrIndex == `1` && @[0].ProcessedData.VariableData"));
c:[type=="bootOrderFound", issuer=="AttestationPolicy"] => issue(type="bootOrder", value=JsonToClaimValue(c.value));
![type=="bootOrderFound", issuer=="AttestationPolicy"] => issue(type="bootOrder", value=0);
// Look for "Secure Boot" from EFI Driver Configuration Data
c:[type == "efiConfigVariables", issuer=="AttestationPolicy"] => issue(type = "secureBootEnabled", value = JsonToClaimValue(JmesPath(c.value, "[?ProcessedData.UnicodeName == 'SecureBoot'] | length(@) == `1` && @[0].PcrIndex == `7` && @[0].ProcessedData.VariableData == 'AQ'")));
![type=="secureBootEnabled", issuer=="AttestationPolicy"] => issue(type="secureBootEnabled", value=false);
// Look for "Platform Key" from EFI Boot Data
c:[type == "efiConfigVariables", issuer=="AttestationPolicy"] => add(type = "platformKeyFound", value = JmesPath(c.value, "[?ProcessedData.UnicodeName == 'PK'] | length(@) == `1` && @[0].PcrIndex == `7` && @[0].ProcessedData.VariableData"));
c:[type=="platformKeyFound", issuer=="AttestationPolicy"] => issue(type="platformKey", value=JsonToClaimValue(c.value));
![type=="platformKeyFound", issuer=="AttestationPolicy"] => issue(type="platformKey", value=0);
// Look for "Key Exchange Key" from EFI Driver Configuration Data
c:[type == "efiConfigVariables", issuer=="AttestationPolicy"] => add(type = "keyExchangeKeyFound", value = JmesPath(c.value, "[?ProcessedData.UnicodeName == 'KEK'] | length(@) == `1` && @[0].PcrIndex == `7` && @[0].ProcessedData.VariableData"));
c:[type=="keyExchangeKeyFound", issuer=="AttestationPolicy"] => issue(type="keyExchangeKey", value=JsonToClaimValue(c.value));
![type=="keyExchangeKeyFound", issuer=="AttestationPolicy"] => issue(type="keyExchangeKey", value=0);
// Look for "Key Database" from EFI Driver Configuration Data
c:[type == "efiConfigVariables", issuer=="AttestationPolicy"] => add(type = "keyDatabaseFound", value = JmesPath(c.value, "[?ProcessedData.UnicodeName == 'db'] | length(@) == `1` && @[0].PcrIndex == `7` && @[0].ProcessedData.VariableData"));
c:[type=="keyDatabaseFound", issuer=="AttestationPolicy"] => issue(type="keyDatabase", value=JsonToClaimValue(c.value));
![type=="keyDatabaseFound", issuer=="AttestationPolicy"] => issue(type="keyDatabase", value=0);
// Look for "Forbidden Signatures" from EFI Driver Configuration Data
c:[type == "efiConfigVariables", issuer=="AttestationPolicy"] => add(type = "forbiddenSignaturesFound", value = JmesPath(c.value, "[?ProcessedData.UnicodeName == 'dbx'] | length(@) == `1` && @[0].PcrIndex == `7` && @[0].ProcessedData.VariableData"));
c:[type=="forbiddenSignaturesFound", issuer=="AttestationPolicy"] => issue(type="forbiddenSignatures", value=JsonToClaimValue(c.value));
![type=="forbiddenSignaturesFound", issuer=="AttestationPolicy"] => issue(type="forbiddenSignatures", value=0);
// Look for "Kernel Version" in IMA Measurement events
c:[type=="imaMeasurementEvents", issuer=="AttestationPolicy"] => add(type="kernelVersionsFound", value=JmesPath(c.value, "[].ProcessedData.KernelVersion"));
c:[type=="kernelVersionsFound", issuer=="AttestationPolicy"] => issue(type="kernelVersions", value=JsonToClaimValue(c.value));
![type=="kernelVersionsFound", issuer=="AttestationPolicy"] => issue(type="kernelVersions", value=0);
// Look for "Built-In Trusted Keys" in IMA Measurement events
c:[type=="imaMeasurementEvents", issuer=="AttestationPolicy"] => add(type="builtintrustedkeysFound", value=JmesPath(c.value, "[? ProcessedData.Keyring == '.builtin_trusted_keys'].ProcessedData.CertificateSubject"));
c:[type=="builtintrustedkeysFound", issuer=="AttestationPolicy"] => issue(type="builtintrustedkeys", value=JsonToClaimValue(c.value));
![type=="builtintrustedkeysFound", issuer=="AttestationPolicy"] => issue(type="builtintrustedkeys", value=0);
};
참고: 비 파일 기반 측정에 대한 지원은 Linux 커널 버전 5.15에서만 사용할 수 있습니다.
TPM 키 증명 지원
수많은 애플리케이션은 자격 증명 도난으로부터 보호하기 위해 키 및 인증서의 기본 자격 증명 관리에 의존하며, 자격 증명 보안을 보장하는 기본 방법 중 하나는 맬웨어 및 공격으로부터 추가 보안을 제공하는 키 스토리지 공급자에 의존하는 것입니다. Windows는 소프트웨어 또는 하드웨어 기반일 수 있는 다양한 암호화 공급자를 구현합니다.
가장 중요한 두 가지는 다음과 같습니다.
Microsoft 소프트웨어 키 스토리지 공급자: 키 소프트웨어를 기반으로 저장하고 CNG(Crypto-Next Generation)를 지원하는 표준 공급자
Microsoft 플랫폼 암호화 공급자: TPM(신뢰할 수 있는 플랫폼 모듈)에 키를 저장하고 CNG를 지원하는 기반 하드웨어
스토리지 공급자를 사용할 때마다 일반적으로 신뢰 루트에 연결된 pub/priv 키 쌍을 만듭니다. 만들 때 더 많은 속성을 사용하여 키 스토리지, 내보내기 가능성 등의 특정 측면을 사용하도록 설정할 수도 있습니다. 이 컨텍스트에서 키 증명은 프라이빗 키가 내부에서 생성되었으며 내부에서 내보낼 수 없는 형태로 관리된다는 것을 회신 당사자에게 증명하는 기술 기능입니다. 다른 정보가 포함된 이러한 증명은 자격 증명 도난 및 재생 유형의 공격으로부터 보호하는 데 도움이 될 수 있습니다.
또한 TPM은 키가 TPM에 상주한다는 것을 증명하여 내보내기 방지 기능, 손상 방지 및 키 격리를 통한 더 높은 보안 보증을 실현하는 기능도 제공합니다. 일반적인 사용 사례는 구독자 키에 대한 디지털 서명 인증서를 발급하는 애플리케이션에서 구독자 프라이빗 서명 키가 승인된 TPM에서 생성되고 관리되는지 확인하는 것입니다. 아래와 같이 정책을 사용하여 적절한 Nonexportability 플래그가 있는 유효한 TPM에 키가 상주하고 있다는 사실을 쉽게 입증할 수 있습니다.
version=1.2;
authorizationrules
{
=> permit();
};
issuancerules
{
// Key Attest Policy
// -- Validating key types
c:[type=="x-ms-tpm-request-key", issuer=="AttestationService"] => add(type="requestKeyType", value=JsonToClaimValue(JmesPath(c.value, "jwk.kty")));
c:[type=="x-ms-tpm-other-keys", issuer=="AttestationService"] => add(type="otherKeysTypes", value=JsonToClaimValue(JmesPath(c.value, "[*].jwk.kty")));
c:[type=="requestKeyType", issuer=="AttestationPolicy", value=="RSA"] => issue(type="requestKeyType", value="RSA");
c:[type=="otherKeysTypes", issuer=="AttestationPolicy", value=="RSA"] => issue(type="otherKeysTypes", value="RSA");
// -- Validating tpm_quote attributes
c:[type=="x-ms-tpm-request-key", issuer=="AttestationService"] => add(type="requestKeyQuote", value=JmesPath(c.value, "info.tpm_quote"));
c:[type=="requestKeyQuote", issuer=="AttestationPolicy"] => add(type="requestKeyQuoteHashAlg", value=JsonToClaimValue(JmesPath(c.value, "hash_alg")));
c:[type=="requestKeyQuoteHashAlg", issuer=="AttestationPolicy", value=="sha-256"] => issue(type="requestKeyQuoteHashAlg", value="sha-256");
// -- Validating tpm_certify attributes
c:[type=="x-ms-tpm-request-key", issuer=="AttestationService"] => add(type="requestKeyCertify", value=JmesPath(c.value, "info.tpm_certify"));
c:[type=="requestKeyCertify", issuer=="AttestationPolicy"] => add(type="requestKeyCertifyNameAlg", value=JsonToClaimValue(JmesPath(c.value, "name_alg")));
c:[type=="requestKeyCertifyNameAlg", issuer=="AttestationPolicy", value==11] => issue(type="requestKeyCertifyNameAlg", value=11);
c:[type=="requestKeyCertify", issuer=="AttestationPolicy"] => add(type="requestKeyCertifyObjAttr", value=JsonToClaimValue(JmesPath(c.value, "obj_attr")));
c:[type=="requestKeyCertifyObjAttr", issuer=="AttestationPolicy", value==50] => issue(type="requestKeyCertifyObjAttr", value=50);
c:[type=="requestKeyCertify", issuer=="AttestationPolicy"] => add(type="requestKeyCertifyAuthPolicy", value=JsonToClaimValue(JmesPath(c.value, "auth_policy")));
c:[type=="requestKeyCertifyAuthPolicy", issuer=="AttestationPolicy", value=="AQIDBA"] => issue(type="requestKeyCertifyAuthPolicy", value="AQIDBA");
c:[type=="x-ms-tpm-other-keys", issuer=="AttestationService"] => add(type="otherKeysCertify", value=JmesPath(c.value, "[*].info.tpm_certify"));
c:[type=="otherKeysCertify", issuer=="AttestationPolicy"] => add(type="otherKeysCertifyNameAlgs", value=JsonToClaimValue(JmesPath(c.value, "[*].name_alg")));
c:[type=="otherKeysCertifyNameAlgs", issuer=="AttestationPolicy", value==11] => issue(type="otherKeysCertifyNameAlgs", value=11);
c:[type=="otherKeysCertify", issuer=="AttestationPolicy"] => add(type="otherKeysCertifyObjAttr", value=JsonToClaimValue(JmesPath(c.value, "[*].obj_attr")));
c:[type=="otherKeysCertifyObjAttr", issuer=="AttestationPolicy", value==50] => issue(type="otherKeysCertifyObjAttr", value=50);
c:[type=="otherKeysCertify", issuer=="AttestationPolicy"] => add(type="otherKeysCertifyAuthPolicy", value=JsonToClaimValue(JmesPath(c.value, "[*].auth_policy")));
c:[type=="otherKeysCertifyAuthPolicy", issuer=="AttestationPolicy", value=="AQIDBA"] => issue(type="otherKeysCertifyAuthPolicy", value="AQIDBA");
};