추가 완화 사항
Credential Guard는 파생 자격 증명에 대한 공격에 대한 완화를 제공하여 다른 곳에서 도난당한 자격 증명의 사용을 방지합니다. 그러나 파생 자격 증명이 Credential Guard로 보호되더라도 디바이스는 여전히 특정 공격에 취약할 수 있습니다. 이러한 공격에는 권한 남용 및 손상된 디바이스에서 직접 파생 자격 증명 사용, Credential Guard를 사용하도록 설정하기 전에 도난당한 자격 증명 다시 사용, 관리 도구 남용 및 약한 애플리케이션 구성이 포함될 수 있습니다. 이 때문에 도메인 환경을 보다 강력하게 만들려면 추가 완화도 배포해야 합니다.
추가 보안 자격
하드웨어, 펌웨어 및 소프트웨어에 대한 기준 보호를 충족하는 모든 디바이스는 Credential Guard를 사용할 수 있습니다.
더 많은 자격을 충족하는 디바이스는 공격 표면을 더욱 줄이기 위해 추가 보호를 제공할 수 있습니다.
다음 표에는 향상된 보안에 대한 자격이 나와 있습니다. Credential Guard가 제공할 수 있는 보안 수준을 강화하기 위해 추가 자격을 충족하는 것이 좋습니다.
보호 | 요구 사항 | 보안 이점: |
---|---|---|
보안 부팅 구성 및 관리 | - BIOS 암호 또는 더 강력한 인증이 지원 되어야 함 - BIOS 구성에서 BIOS 인증을 설정 해야 합니다. 허용된 부팅 디바이스 목록(예: 내부 하드 드라이브에서만 부팅) 및 부팅 디바이스 순서를 구성하고 운영 체제에서 수정한 수정 사항을 재정의하는 BOOTORDER 보호된 BIOS 옵션이 지원되어야 합니다. |
- 다른 운영 체제가 시작되지 않도록 방지 -BIOS 설정 변경 방지 |
하드웨어 루트 트러스트 플랫폼 보안 부팅 | - 부팅 무결성(플랫폼 보안 부팅)이 지원되어야 합니다. System.Fundamentals.Firmware.CS.UEFISecureBoot.ConnectedStandby - HSTI(하드웨어 보안 테스트 인터페이스)를 구현해야 하는 Windows 하드웨어 호환성 프로그램 요구 사항을 참조하세요. 하드웨어 보안 테스트 가능성 사양을 참조하세요. |
- 전원 공급의 부팅 무결성(플랫폼 보안 부팅)에서 실제로 존재하는 공격자에 대한 보호 기능과 맬웨어에 대한 심층적인 방어 수단을 제공합니다.
- HSTI는 올바르게 보안된 실리콘 및 플랫폼에 대한 보안 보증을 제공합니다. |
Windows 업데이트를 통한 펌웨어 업데이트 | - 펌웨어는 Windows 업데이트 및 UEFI 캡슐화 업데이트를 통해 필드 업데이트를 지원해야 합니다. | 펌웨어 업데이트가 빠르고 안전하고 안정적이 되도록 보장합니다. |
부팅 구성 및 관리 보안 | - 필수 BIOS 기능: 제조 시 보안 부팅 DB에 ISV, OEM 또는 엔터프라이즈 인증서를 추가하는 OEM 기능 - 필수 구성: Microsoft UEFI CA를 보안 부팅 DB에서 제거해야 합니다. 타사 UEFI 모듈에 대한 지원은 허용되지만 특정 UEFI 소프트웨어에 ISV 제공 인증서 또는 OEM 인증서를 사용해야 합니다. |
- 엔터프라이즈는 독점 EFI 드라이버/애플리케이션 실행을 허용하도록 선택할 수 있습니다. 보안 부팅 DB에서 Microsoft UEFI CA를 제거하면 운영 체제가 부팅되기 전에 실행되는 소프트웨어에 대한 모든 권한이 기업에 제공됩니다. |
UEFI 런타임 서비스에 대한 NX(No-Execute) 보호의 VBS 사용 | - VBS는 UEFI 런타임 서비스 코드 및 데이터 메모리 영역에서 NX 보호를 사용하도록 설정합니다. UEFI 런타임 서비스 코드는 읽기 전용 페이지 보호를 지원해야 하며 UEFI 런타임 서비스 데이터는 실행될 수 없어야 합니다. UEFI 런타임 서비스는 다음 요구 사항을 충족해야 합니다. - UEFI 2.6 EFI_MEMORY_ATTRIBUTES_TABLE 구현. 모든 UEFI 런타임 서비스 메모리(코드 및 데이터)는 이 표 에서 설명해야 합니다. PE 섹션은 메모리에서 페이지 정렬되어야 합니다(비휘발성 스토리지에는 필요하지 않음). - 메모리 특성 테이블은 OS 의 구성에 대한 코드 및 데이터를 RO/NX 올바르게 표시해야 합니다. 모든 항목에는 특성 EFI_MEMORY_RO , EFI_MEMORY_XP 또는 둘 다를 포함해야 합니다.
- 실행 파일과 쓰기 가능한 메모리를 나타내는 위의 특성 중 어느 것도 입력하지 않을 수 있습니다. 메모리는 읽기 가능하고 실행 가능하거나 쓰기 가능하며 실행 불가능 해야 합니다(이 테이블 이후의 중요 정보 참조). |
- UEFI 런타임의 취약성(있는 경우)이 VBS 손상(예: UpdateCapsule 및 SetVariable과 같은 함수) 에서 차단됨 - 시스템 펌웨어에서 VBS로 공격 노출 영역을 줄입니다. |
SMM 보호를 위한 펌웨어 지원 | - WSMT(Windows SMM 보안 완화 테이블) 사양 에는 Windows 가상화 기반 기능을 지원하는 Windows 운영 체제에서 사용하기 위해 만든 ACPI 테이블의 세부 정보가 포함되어 있습니다. | - UEFI 런타임 서비스의 잠재적 취약성(있는 경우)이 VBS 손상으로부터 차단됩니다(예: UpdateCapsule 및 SetVariable과 같은 함수). - 시스템 펌웨어에서 VBS로 공격 표면 감소 - SMM에 대한 추가 보안 공격 차단 |
중요
UEFI 런타임 서비스에 대한 NX 보호의 VBS 사용과 관련하여 다음을 수행합니다.
- UEFI 부팅 서비스 메모리가 아닌 UEFI 런타임 서비스 메모리에만 적용됩니다.
- 보호는 OS 페이지 테이블의 VBS에 의해 적용됩니다.
- 쓰기 가능 및 실행 파일인 섹션을 사용하지 마세요.
- 실행 파일 시스템 메모리를 직접 수정하지 마세요.
- 동적 코드를 사용하지 마세요.
도메인 사용자를 특정 도메인 가입 디바이스로 제한
자격 증명 도난 공격을 통해 공격자는 한 장치의 암호를 가져와 다른 장치에서 도용할 수 있습니다. 사용자가 여러 장치에 로그온할 수 있는 경우 임의 장치를 사용하여 자격 증명을 도용할 수 있습니다. 사용자가 Credential Guard를 사용하도록 설정된 디바이스에서만 로그온하도록 하려면 어떻게 해야 할까요? Credential Guard로 구성된 특정 도메인 가입 디바이스로 제한하는 인증 정책을 배포합니다. 도메인 컨트롤러에서 사용자가 로그온하는 장치를 파악하려면 Kerberos 아머링(armoring)을 사용해야 합니다.
Kerberos 아머링(armoring)
Kerberos 아머링(armoring)은 RFC 6113의 일부입니다. 장치에서 Kerberos 아머링(armoring)을 지원하는 경우 TGT를 사용하여 오프라인 사전 공격을 완화할 수 있는 사용자의 소유 증거를 보호합니다. Kerberos 아머링(armoring)에서는 서명된 KDC 오류의 이점도 추가로 제공합니다. 그러면 다운그레이드 공격과 같은 문제를 초래할 수 있는 변조가 완화됩니다.
도메인 사용자를 특정 도메인 가입 디바이스로 제한하기 위해 Kerberos 아머링을 사용하도록 설정하려면 다음을 수행합니다.
- 사용자가 Windows Server 2012 R2 이상을 실행 중인 도메인에 있어야 함
- 이러한 도메인에 있는 모든 도메인 컨트롤러는 Kerberos 아머링(armoring)을 지원하도록 구성해야 합니다. 클레임, 복합 인증 및 Kerberos 아머링 그룹 정책 설정에 대한 KDC 지원을지원되거나항상 클레임 제공으로 설정합니다.
- 사용자가 제한될 Credential Guard가 있는 모든 디바이스는 Kerberos 아머링을 지원하도록 구성해야 합니다. 컴퓨터 구성>관리 템플릿시스템>Kerberos에서 클레임, 복합 인증 및 Kerberos 아머링 그룹 정책 설정에 >대해 Kerberos 클라이언트 지원을 사용하도록 설정합니다.
도메인에 가입된 디바이스 비밀 보호
도메인에 가입된 디바이스에서는 인증을 위해 공유 암호도 사용하므로, 공격자는 이 암호도 도용할 수 있습니다. Credential Guard로 디바이스 자격 증명을 배포하여 개인 키를 보호할 수 있습니다. 그런 다음 인증 정책에서 사용자가 해당 인증서를 사용하여 인증하는 디바이스에 로그온하도록 요구할 수 있습니다. 그러면 장치에서 도난된 공유 암호와 도난된 사용자 자격 증명을 함께 사용하여 해당 사용자로 로그인하지 못하게 됩니다.
도메인에 가입된 장치 인증서 인증에는 다음 요구 사항이 적용됩니다.
- 장치의 계정이 Windows Server 2012 도메인 기능 수준 이상에 속해 있습니다.
- 이러한 도메인의 모든 도메인 컨트롤러에는 엄격한 KDC 유효성 검사 인증서 요구 사항을 충족하는 KDC 인증서가 있습니다.
- KDC EKU 있음
- DNS 도메인 이름이 SAN(SubjectAltName) 확장의 DNSName 필드와 일치합니다.
- Windows 디바이스에는 CA가 엔터프라이즈 저장소에서 도메인 컨트롤러 인증서를 발급합니다.
- 스마트 카드를 발급하기 전에 사용자의 ID 및 신뢰성을 설정하는 것과 유사한 방식으로 장치의 ID 및 신뢰성을 보장하도록 프로세스가 설정됩니다.
도메인에 가입된 디바이스 인증서 배포
해당 사용자가 사용해야 하는 장치에만 필요한 발급 정책과 함께 인증서가 설치되도록 각 장치에서 수동으로 인증서를 배포해야 합니다. 사용자에게 스마트 카드를 발급하는 데 사용되는 동일한 보안 절차를 장치 인증서에 적용해야 합니다.
예를 들어 해당 장치에서 높은 보증 정책을 사용하려 한다고 가정합니다. Windows Server Enterprise 인증 기관을 사용하여 새로운 템플릿을 만듭니다.
새 인증서 템플릿 만들기
- 인증서 관리자 콘솔에서 인증서 템플릿 관리를 마우스 오른쪽 단추로 클릭합니다.>
- 워크스테이션 인증 > 중복 템플릿을 마우스 오른쪽 단추로 클릭
- 새 템플릿을 마우스 오른쪽 단추로 클릭한 다음 속성을 선택합니다.
- 확장 탭에서 애플리케이션 정책 > 편집을 선택합니다.
- 클라이언트 인증을 선택한 다음 제거를 선택합니다.
- ID-PKInit-KPClientAuth EKU를 추가합니다.
새로 추가>를 선택한 다음, 다음 값을 지정합니다.
- 이름: Kerberos Client Auth
- 개체 식별자: 1.3.6.1.5.2.3.4
- 확장 탭에서 발급 정책 > 편집을 선택합니다.
- 발급 정책에서 High Assurance를 선택합니다.
- 주체 이름 탭에서 DNS 이름 확인란의 선택을 취소한 다음 UPN(사용자 계정 이름) 확인란을 선택합니다.
그런 다음 Credential Guard를 실행하는 디바이스에서 만든 인증서를 사용하여 디바이스를 등록합니다.
인증서에 디바이스 등록
다음 명령을 실행합니다.
CertReq -EnrollCredGuardCert MachineAuthentication
참고
컴퓨터 인증 인증서를 등록한 후에는 장치를 다시 시작해야 합니다.
액세스 컨트롤에 인증서 발급 정책을 사용하는 방법
Windows Server 2008 R2 도메인 기능 수준부터 인증 메커니즘 보증에 대한 도메인 컨트롤러 지원에서 인증서 발급 정책 OID를 범용 보안 그룹에 매핑하는 방법을 제공합니다. 클레임이 포함된 Windows Server 2012 도메인 지원에서는 해당 OID를 클레임에 매핑할 수 있습니다. 인증 메커니즘 보증에 대한 자세한 정보는 TechNet에 있는 Windows Server 2008 R2 단계별 가이드의 AD DS용 인증 메커니즘 보증을 참조하세요.
사용 가능한 발급 정책 확인
-
get-IssuancePolicy.ps1은 인증 기관에 대해 사용 가능한 모든 발급 정책을 보여 줍니다.
Windows PowerShell 명령 프롬프트에서 다음 명령을 실행합니다.
.\get-IssuancePolicy.ps1 -LinkedToGroup:All
발급 정책을 유니버설 보안 그룹에 연결
-
set-IssuancePolicyToGroupLink.ps1은 유니버설 보안 그룹과 조직 구성 단위를 만들고 발급 정책을 이 유니버설 보안 그룹에 연결합니다.
Windows PowerShell 명령 프롬프트에서 다음 명령을 실행합니다.
.\set-IssuancePolicyToGroupLink.ps1 -IssuancePolicyName:"<name of issuance policy>" -groupOU:"<Name of OU to create>" -groupName:"<name of Universal security group to create>"
사용자 로그온 제한
이제 다음과 같은 작업을 완료했습니다.
- 사용자가 로그온하는 데 필요한 배포 기준을 만족하는 장치를 식별하기 위한 특수 인증서 발급 정책을 만듦
- 해당 정책을 범용 보안 그룹 또는 클레임에 매핑함
- Kerberos 아머링을 사용하여 사용자 로그온 중에 도메인 컨트롤러가 디바이스 권한 부여 데이터를 가져올 수 있는 방법을 제공했습니다. 이제 남은 작업은 도메인 컨트롤러에서 액세스 검사를 구성하는 것입니다. 이 작업은 인증 정책을 사용하여 수행됩니다.
인증 정책에는 다음과 같은 요구 사항이 있습니다.
- 사용자 계정은 Windows Server 2012 도메인 기능 수준 이상 도메인에 있습니다.
사용자를 특정 범용 보안 그룹으로 제한하는 인증 정책 만들기
- Active Directory 관리 센터 열기
- 인증 > 새 > 인증 정책 선택
- 표시 이름 상자에 이 인증 정책의 이름을 입력합니다.
- 계정 제목 아래에서 추가를 선택합니다.
- 사용자, 컴퓨터 또는 서비스 계정 선택 대화 상자에서 제한하려는 사용자 계정의 이름을 입력한 다음 확인을 선택합니다.
- 사용자 로그온 제목 아래에서 편집 단추를 선택합니다.
- 조건 추가를 선택합니다.
- 액세스 제어 조건 편집 상자에서 각 > 값의 사용자 > 그룹 > 구성원을 읽은 다음 항목 추가를 선택합니다.
- 사용자, 컴퓨터 또는 서비스 계정 선택 대화 상자에서 set-IssuancePolicyToGroupLink 스크립트를 사용하여 만든 유니버설 보안 그룹의 이름을 입력한 다음 확인을 선택합니다.
- 확인을 선택하여 액세스 제어 조건 편집 상자를 닫습니다.
- 확인을 선택하여 인증 정책을 만듭니다.
- Active Directory 관리 센터 선택
참고
인증 정책에서 정책 제한사항을 적용하면 사용자가 적절한 보증 정책이 배포된 인증서가 없는 장치를 사용하여 로그인할 수 없습니다. 이는 로컬 및 원격 로그인 시나리오에 모두 적용됩니다. 따라서 예기치 않게 실패하지 않도록 먼저 정책 제한사항만 감사하는 것이 좋습니다.
인증 정책으로 인한 인증 실패 검색
인증 정책으로 인한 인증 실패를 더 쉽게 추적할 수 있도록 해당 이벤트만 포함된 작업 로그가 있습니다. 도메인 컨트롤러에서 로그를 사용하도록 설정하려면 이벤트 뷰어에서 애플리케이션 및 서비스 로그\Microsoft\Windows\Authentication으로 이동하고 AuthenticationPolicyFailures-DomainController를 마우스 오른쪽 단추로 클릭한 다음 로그 사용을 선택합니다.
인증 정책 이벤트에 대한 자세한 정보는 인증 정책 및 인증 정책 사일로를 참조하세요.
부록: 스크립트
다음은 이 문서에 언급된 스크립트 목록입니다.
인증 기관에서 사용 가능한 발급 정책 가져오기
다음 스크립트 파일을 get-IssuancePolicy.ps1로 저장합니다.
#######################################
## Parameters to be defined ##
## by the user ##
#######################################
Param (
$Identity,
$LinkedToGroup
)
#######################################
## Strings definitions ##
#######################################
Data getIP_strings {
# culture="en-US"
ConvertFrom-StringData -stringdata @'
help1 = This command can be used to retrieve all available Issuance Policies in a forest. The forest of the currently logged on user is targeted.
help2 = Usage:
help3 = The following parameter is mandatory:
help4 = -LinkedToGroup:<yes|no|all>
help5 = "yes" will return only Issuance Policies that are linked to groups. Checks that the linked Issuance Policies are linked to valid groups.
help6 = "no" will return only Issuance Policies that are not currently linked to any group.
help7 = "all" will return all Issuance Policies defined in the forest. Checks that the linked Issuance policies are linked to valid groups.
help8 = The following parameter is optional:
help9 = -Identity:<Name, Distinguished Name or Display Name of the Issuance Policy that you want to retrieve>. If you specify an identity, the option specified in the "-LinkedToGroup" parameter is ignored.
help10 = Output: This script returns the Issuance Policy objects meeting the criteria defined by the above parameters.
help11 = Examples:
errorIPNotFound = Error: no Issuance Policy could be found with Identity "{0}"
ErrorNotSecurity = Error: Issuance Policy "{0}" is linked to group "{1}" which is not of type "Security".
ErrorNotUniversal = Error: Issuance Policy "{0}" is linked to group "{1}" whose scope is not "Universal".
ErrorHasMembers = Error: Issuance Policy "{0}" is linked to group "{1}" which has a non-empty membership. The group has the following members:
LinkedIPs = The following Issuance Policies are linked to groups:
displayName = displayName : {0}
Name = Name : {0}
dn = distinguishedName : {0}
InfoName = Linked Group Name: {0}
InfoDN = Linked Group DN: {0}
NonLinkedIPs = The following Issuance Policies are NOT linked to groups:
'@
}
##Import-LocalizedData getIP_strings
import-module ActiveDirectory
#######################################
## Help ##
#######################################
function Display-Help {
""
$getIP_strings.help1
""
$getIP_strings.help2
""
$getIP_strings.help3
" " + $getIP_strings.help4
" " + $getIP_strings.help5
" " + $getIP_strings.help6
" " + $getIP_strings.help7
""
$getIP_strings.help8
" " + $getIP_strings.help9
""
$getIP_strings.help10
""
""
$getIP_strings.help11
" " + '$' + "myIPs = .\get-IssuancePolicy.ps1 -LinkedToGroup:All"
" " + '$' + "myLinkedIPs = .\get-IssuancePolicy.ps1 -LinkedToGroup:yes"
" " + '$' + "myIP = .\get-IssuancePolicy.ps1 -Identity:""Medium Assurance"""
""
}
$root = get-adrootdse
$domain = get-addomain -current loggedonuser
$configNCDN = [String]$root.configurationNamingContext
if ( !($Identity) -and !($LinkedToGroup) ) {
display-Help
break
}
if ($Identity) {
$OIDs = get-adobject -Filter {(objectclass -eq "msPKI-Enterprise-Oid") -and ((name -eq $Identity) -or (displayname -eq $Identity) -or (distinguishedName -like $Identity)) } -searchBase $configNCDN -properties *
if ($OIDs -eq $null) {
$errormsg = $getIP_strings.ErrorIPNotFound -f $Identity
write-host $errormsg -ForegroundColor Red
}
foreach ($OID in $OIDs) {
if ($OID."msDS-OIDToGroupLink") {
# In case the Issuance Policy is linked to a group, it is good to check whether there is any problem with the mapping.
$groupDN = $OID."msDS-OIDToGroupLink"
$group = get-adgroup -Identity $groupDN
$groupName = $group.Name
# Analyze the group
if ($group.groupCategory -ne "Security") {
$errormsg = $getIP_strings.ErrorNotSecurity -f $Identity, $groupName
write-host $errormsg -ForegroundColor Red
}
if ($group.groupScope -ne "Universal") {
$errormsg = $getIP_strings.ErrorNotUniversal -f $Identity, $groupName
write-host $errormsg -ForegroundColor Red
}
$members = Get-ADGroupMember -Identity $group
if ($members) {
$errormsg = $getIP_strings.ErrorHasMembers -f $Identity, $groupName
write-host $errormsg -ForegroundColor Red
foreach ($member in $members) {
write-host " " $member -ForeGroundColor Red
}
}
}
}
return $OIDs
break
}
if (($LinkedToGroup -eq "yes") -or ($LinkedToGroup -eq "all")) {
$LDAPFilter = "(&(objectClass=msPKI-Enterprise-Oid)(msDS-OIDToGroupLink=*)(flags=2))"
$LinkedOIDs = get-adobject -searchBase $configNCDN -LDAPFilter $LDAPFilter -properties *
write-host ""
write-host "*****************************************************"
write-host $getIP_strings.LinkedIPs
write-host "*****************************************************"
write-host ""
if ($LinkedOIDs -ne $null){
foreach ($OID in $LinkedOIDs) {
# Display basic information about the Issuance Policies
""
$getIP_strings.displayName -f $OID.displayName
$getIP_strings.Name -f $OID.Name
$getIP_strings.dn -f $OID.distinguishedName
# Get the linked group.
$groupDN = $OID."msDS-OIDToGroupLink"
$group = get-adgroup -Identity $groupDN
$getIP_strings.InfoName -f $group.Name
$getIP_strings.InfoDN -f $groupDN
# Analyze the group
$OIDName = $OID.displayName
$groupName = $group.Name
if ($group.groupCategory -ne "Security") {
$errormsg = $getIP_strings.ErrorNotSecurity -f $OIDName, $groupName
write-host $errormsg -ForegroundColor Red
}
if ($group.groupScope -ne "Universal") {
$errormsg = $getIP_strings.ErrorNotUniversal -f $OIDName, $groupName
write-host $errormsg -ForegroundColor Red
}
$members = Get-ADGroupMember -Identity $group
if ($members) {
$errormsg = $getIP_strings.ErrorHasMembers -f $OIDName, $groupName
write-host $errormsg -ForegroundColor Red
foreach ($member in $members) {
write-host " " $member -ForeGroundColor Red
}
}
write-host ""
}
}else{
write-host "There are no issuance policies that are mapped to a group"
}
if ($LinkedToGroup -eq "yes") {
return $LinkedOIDs
break
}
}
if (($LinkedToGroup -eq "no") -or ($LinkedToGroup -eq "all")) {
$LDAPFilter = "(&(objectClass=msPKI-Enterprise-Oid)(!(msDS-OIDToGroupLink=*))(flags=2))"
$NonLinkedOIDs = get-adobject -searchBase $configNCDN -LDAPFilter $LDAPFilter -properties *
write-host ""
write-host "*********************************************************"
write-host $getIP_strings.NonLinkedIPs
write-host "*********************************************************"
write-host ""
if ($NonLinkedOIDs -ne $null) {
foreach ($OID in $NonLinkedOIDs) {
# Display basic information about the Issuance Policies
write-host ""
$getIP_strings.displayName -f $OID.displayName
$getIP_strings.Name -f $OID.Name
$getIP_strings.dn -f $OID.distinguishedName
write-host ""
}
}else{
write-host "There are no issuance policies which are not mapped to groups"
}
if ($LinkedToGroup -eq "no") {
return $NonLinkedOIDs
break
}
}
참고
이 스크립트를 실행하는 데 문제가 있는 경우에는 ConvertFrom-StringData 매개 변수 뒤에 있는 작은따옴표를 바꿔 보세요.
그룹에 발급 정책 연결
다음 스크립트 파일을 set-IssuancePolicyToGroupLink.ps1로 저장합니다.
#######################################
## Parameters to be defined ##
## by the user ##
#######################################
Param (
$IssuancePolicyName,
$groupOU,
$groupName
)
#######################################
## Strings definitions ##
#######################################
Data ErrorMsg {
# culture="en-US"
ConvertFrom-StringData -stringdata @'
help1 = This command can be used to set the link between a certificate issuance policy and a universal security group.
help2 = Usage:
help3 = The following parameters are required:
help4 = -IssuancePolicyName:<name or display name of the issuance policy that you want to link to a group>
help5 = -groupName:<name of the group you want to link the issuance policy to>. If no name is specified, any existing link to a group is removed from the Issuance Policy.
help6 = The following parameter is optional:
help7 = -groupOU:<Name of the Organizational Unit dedicated to the groups which are linked to issuance policies>. If this parameter is not specified, the group is looked for or created in the Users container.
help8 = Examples:
help9 = This command will link the issuance policy whose display name is "High Assurance" to the group "HighAssuranceGroup" in the Organizational Unit "OU_FOR_IPol_linked_groups". If the group or the Organizational Unit do not exist, you will be prompted to create them.
help10 = This command will unlink the issuance policy whose name is "402.164959C40F4A5C12C6302E31D5476062" from any group.
MultipleIPs = Error: Multiple Issuance Policies with name or display name "{0}" were found in the subtree of "{1}"
NoIP = Error: no issuance policy with name or display name "{0}" could be found in the subtree of "{1}".
IPFound = An Issuance Policy with name or display name "{0}" was successfully found: {1}
MultipleOUs = Error: more than 1 Organizational Unit with name "{0}" could be found in the subtree of "{1}".
confirmOUcreation = Warning: The Organizational Unit that you specified does not exist. Do you want to create it?
OUCreationSuccess = Organizational Unit "{0}" successfully created.
OUcreationError = Error: Organizational Unit "{0}" could not be created.
OUFoundSuccess = Organizational Unit "{0}" was successfully found.
multipleGroups = Error: More than one group with name "{0}" was found in Organizational Unit "{1}".
confirmGroupCreation = Warning: The group that you specified does not exist. Do you want to create it?
groupCreationSuccess = Univeral Security group "{0}" successfully created.
groupCreationError = Error: Univeral Security group "{0}" could not be created.
GroupFound = Group "{0}" was successfully found.
confirmLinkDeletion = Warning: The Issuance Policy "{0}" is currently linked to group "{1}". Do you really want to remove the link?
UnlinkSuccess = Certificate issuance policy successfully unlinked from any group.
UnlinkError = Removing the link failed.
UnlinkExit = Exiting without removing the link from the issuance policy to the group.
IPNotLinked = The Certificate issuance policy is not currently linked to any group. If you want to link it to a group, you should specify the -groupName option when starting this script.
ErrorNotSecurity = Error: You cannot link issuance Policy "{0}" to group "{1}" because this group is not of type "Security".
ErrorNotUniversal = Error: You cannot link issuance Policy "{0}" to group "{1}" because the scope of this group is not "Universal".
ErrorHasMembers = Error: You cannot link issuance Policy "{0}" to group "{1}" because it has a non-empty membership. The group has the following members:
ConfirmLinkReplacement = Warning: The Issuance Policy "{0}" is currently linked to group "{1}". Do you really want to update the link to point to group "{2}"?
LinkSuccess = The certificate issuance policy was successfully linked to the specified group.
LinkError = The certificate issuance policy could not be linked to the specified group.
ExitNoLinkReplacement = Exiting without setting the new link.
'@
}
# import-localizeddata ErrorMsg
function Display-Help {
""
write-host $ErrorMsg.help1
""
write-host $ErrorMsg.help2
""
write-host $ErrorMsg.help3
write-host "`t" $ErrorMsg.help4
write-host "`t" $ErrorMsg.help5
""
write-host $ErrorMsg.help6
write-host "`t" $ErrorMsg.help7
""
""
write-host $ErrorMsg.help8
""
write-host $ErrorMsg.help9
".\Set-IssuancePolicyToGroupMapping.ps1 -IssuancePolicyName ""High Assurance"" -groupOU ""OU_FOR_IPol_linked_groups"" -groupName ""HighAssuranceGroup"" "
""
write-host $ErrorMsg.help10
'.\Set-IssuancePolicyToGroupMapping.ps1 -IssuancePolicyName "402.164959C40F4A5C12C6302E31D5476062" -groupName $null '
""
}
# Assumption: The group to which the Issuance Policy is going
# to be linked is (or is going to be created) in
# the domain the user running this script is a member of.
import-module ActiveDirectory
$root = get-adrootdse
$domain = get-addomain -current loggedonuser
if ( !($IssuancePolicyName) ) {
display-Help
break
}
#######################################
## Find the OID object ##
## (aka Issuance Policy) ##
#######################################
$searchBase = [String]$root.configurationnamingcontext
$OID = get-adobject -searchBase $searchBase -Filter { ((displayname -eq $IssuancePolicyName) -or (name -eq $IssuancePolicyName)) -and (objectClass -eq "msPKI-Enterprise-Oid")} -properties *
if ($OID -eq $null) {
$tmp = $ErrorMsg.NoIP -f $IssuancePolicyName, $searchBase
write-host $tmp -ForeGroundColor Red
break;
}
elseif ($OID.GetType().IsArray) {
$tmp = $ErrorMsg.MultipleIPs -f $IssuancePolicyName, $searchBase
write-host $tmp -ForeGroundColor Red
break;
}
else {
$tmp = $ErrorMsg.IPFound -f $IssuancePolicyName, $OID.distinguishedName
write-host $tmp -ForeGroundColor Green
}
#######################################
## Find the container of the group ##
#######################################
if ($groupOU -eq $null) {
# default to the Users container
$groupContainer = $domain.UsersContainer
}
else {
$searchBase = [string]$domain.DistinguishedName
$groupContainer = get-adobject -searchBase $searchBase -Filter { (Name -eq $groupOU) -and (objectClass -eq "organizationalUnit")}
if ($groupContainer.count -gt 1) {
$tmp = $ErrorMsg.MultipleOUs -f $groupOU, $searchBase
write-host $tmp -ForegroundColor Red
break;
}
elseif ($groupContainer -eq $null) {
$tmp = $ErrorMsg.confirmOUcreation
write-host $tmp " ( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
new-adobject -Name $groupOU -displayName $groupOU -Type "organizationalUnit" -ProtectedFromAccidentalDeletion $true -path $domain.distinguishedName
if ($?){
$tmp = $ErrorMsg.OUCreationSuccess -f $groupOU
write-host $tmp -ForegroundColor Green
}
else{
$tmp = $ErrorMsg.OUCreationError -f $groupOU
write-host $tmp -ForeGroundColor Red
break;
}
$groupContainer = get-adobject -searchBase $searchBase -Filter { (Name -eq $groupOU) -and (objectClass -eq "organizationalUnit")}
}
else {
break;
}
}
else {
$tmp = $ErrorMsg.OUFoundSuccess -f $groupContainer.name
write-host $tmp -ForegroundColor Green
}
}
#######################################
## Find the group ##
#######################################
if (($groupName -ne $null) -and ($groupName -ne "")){
##$searchBase = [String]$groupContainer.DistinguishedName
$searchBase = $groupContainer
$group = get-adgroup -Filter { (Name -eq $groupName) -and (objectClass -eq "group") } -searchBase $searchBase
if ($group -ne $null -and $group.gettype().isarray) {
$tmp = $ErrorMsg.multipleGroups -f $groupName, $searchBase
write-host $tmp -ForeGroundColor Red
break;
}
elseif ($group -eq $null) {
$tmp = $ErrorMsg.confirmGroupCreation
write-host $tmp " ( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
new-adgroup -samAccountName $groupName -path $groupContainer.distinguishedName -GroupScope "Universal" -GroupCategory "Security"
if ($?){
$tmp = $ErrorMsg.GroupCreationSuccess -f $groupName
write-host $tmp -ForegroundColor Green
}else{
$tmp = $ErrorMsg.groupCreationError -f $groupName
write-host $tmp -ForeGroundColor Red
break
}
$group = get-adgroup -Filter { (Name -eq $groupName) -and (objectClass -eq "group") } -searchBase $searchBase
}
else {
break;
}
}
else {
$tmp = $ErrorMsg.GroupFound -f $group.Name
write-host $tmp -ForegroundColor Green
}
}
else {
#####
## If the group is not specified, we should remove the link if any exists
#####
if ($OID."msDS-OIDToGroupLink" -ne $null) {
$tmp = $ErrorMsg.confirmLinkDeletion -f $IssuancePolicyName, $OID."msDS-OIDToGroupLink"
write-host $tmp " ( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
set-adobject -Identity $OID -Clear "msDS-OIDToGroupLink"
if ($?) {
$tmp = $ErrorMsg.UnlinkSuccess
write-host $tmp -ForeGroundColor Green
}else{
$tmp = $ErrorMsg.UnlinkError
write-host $tmp -ForeGroundColor Red
}
}
else {
$tmp = $ErrorMsg.UnlinkExit
write-host $tmp
break
}
}
else {
$tmp = $ErrorMsg.IPNotLinked
write-host $tmp -ForeGroundColor Yellow
}
break;
}
#######################################
## Verify that the group is ##
## Universal, Security, and ##
## has no members ##
#######################################
if ($group.GroupScope -ne "Universal") {
$tmp = $ErrorMsg.ErrorNotUniversal -f $IssuancePolicyName, $groupName
write-host $tmp -ForeGroundColor Red
break;
}
if ($group.GroupCategory -ne "Security") {
$tmp = $ErrorMsg.ErrorNotSecurity -f $IssuancePolicyName, $groupName
write-host $tmp -ForeGroundColor Red
break;
}
$members = Get-ADGroupMember -Identity $group
if ($members -ne $null) {
$tmp = $ErrorMsg.ErrorHasMembers -f $IssuancePolicyName, $groupName
write-host $tmp -ForeGroundColor Red
foreach ($member in $members) {write-host " $member.name" -ForeGroundColor Red}
break;
}
#######################################
## We have verified everything. We ##
## can create the link from the ##
## Issuance Policy to the group. ##
#######################################
if ($OID."msDS-OIDToGroupLink" -ne $null) {
$tmp = $ErrorMsg.ConfirmLinkReplacement -f $IssuancePolicyName, $OID."msDS-OIDToGroupLink", $group.distinguishedName
write-host $tmp "( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
$tmp = @{'msDS-OIDToGroupLink'= $group.DistinguishedName}
set-adobject -Identity $OID -Replace $tmp
if ($?) {
$tmp = $Errormsg.LinkSuccess
write-host $tmp -Foreground Green
}else{
$tmp = $ErrorMsg.LinkError
write-host $tmp -Foreground Red
}
} else {
$tmp = $Errormsg.ExitNoLinkReplacement
write-host $tmp
break
}
}
else {
$tmp = @{'msDS-OIDToGroupLink'= $group.DistinguishedName}
set-adobject -Identity $OID -Add $tmp
if ($?) {
$tmp = $Errormsg.LinkSuccess
write-host $tmp -Foreground Green
}else{
$tmp = $ErrorMsg.LinkError
write-host $tmp -Foreground Red
}
}
참고
이 스크립트를 실행하는 데 문제가 있는 경우에는 ConvertFrom-StringData 매개 변수 뒤에 있는 작은따옴표를 바꿔 보세요.