Computer >> 컴퓨터 >  >> 시스템 >> Windows Server

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

PowerShell 스크립트 코드 서명이란?

디지털 서명이 포함된 스크립트나 실행 파일은 사용자가 해당 파일이 원본 그대로이며 제3자에 의해 코드가 변조되지 않았음을 확인할 수 있게 해줍니다. 최신 버전의 PowerShell에는 디지털 인증서를 사용해 *.ps1 스크립트 파일에 코드 서명을 수행할 수 있는 내장 도구가 포함되어 있습니다.

코드 서명 인증서 준비하기

PowerShell 스크립트에 서명하려면 CodeSigning(코드 서명) 유형의 특수한 인증서가 필요합니다. 이 인증서는 다음 세 가지 방법으로 확보할 수 있습니다.

  • 외부 상용 인증 기관(CA)에서 발급받기
  • 사내 엔터프라이즈 CA에서 발급받기
  • 자체 서명(self-signed) 인증서 생성하기

엔터프라이즈 CA에서 인증서 요청하기

도메인 환경에 PKI 서비스(Active Directory Certificate Services)가 구축되어 있다면 https://CA-서버이름/certsrv 에 접속하여 Code Signing 템플릿으로 새 인증서를 요청할 수 있습니다. 이때 해당 템플릿은 인증 기관 콘솔에서 미리 사용 가능하도록 설정되어 있어야 합니다.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

또한 MMC 스냅인의 인증서 관리(인증서 -> 내 계정 -> 개인 -> 모든 작업 -> 새 인증서 요청)를 통해서도 PowerShell 스크립트 서명용 인증서를 요청할 수 있습니다.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

인증서를 직접 요청했다면 .cer 확장자를 가진 x509 인증서 파일을 받게 됩니다. 이 인증서는 컴퓨터의 로컬 인증서 저장소에 설치되어야 하며, 아래 PowerShell 명령으로 신뢰할 수 있는 루트 인증 기관 저장소에 추가할 수 있습니다.

$certFile = Export-Certificate -Cert $cert -FilePath C:\ps\certname.cer
Import-Certificate -CertStoreLocation Cert:\LocalMachine\AuthRoot -FilePath $certFile.FullName

자체 서명 인증서 생성하기

테스트 목적 등으로 자체 서명 인증서를 사용하려면 New-SelfSignedCertificate cmdlet으로 CodeSigning 유형의 인증서를 만들 수 있습니다. 예를 들어 DNS 이름이 testPC1인 인증서는 다음과 같이 생성합니다.

New-SelfSignedCertificate -DnsName testPC1 -Type CodeSigning
$cert = New-SelfSignedCertificate -Subject "Cert for Code Signing" -Type CodeSigningCert -DnsName test1 -CertStoreLocation cert:\LocalMachine\My

인증서가 생성된 후에는 인증서 관리 콘솔(certmgr.msc)에서 중간 인증 기관 컨테이너에서 신뢰할 수 있는 루트 인증 기관(Trusted Root) 컨테이너로 옮겨 주어야 합니다.

PowerShell 실행 정책 구성

인증서를 확보했다면, 서명된 스크립트만 실행되도록 PowerShell 스크립트 실행 정책을 구성할 수 있습니다. Windows 10/Windows Server 2016의 기본 실행 정책은 Restricted(모든 PowerShell 스크립트 실행 차단)로 설정되어 있습니다.

File C:\ps\script.ps1 cannot be loaded because running scripts is disabled on this system.

서명된 PS1 스크립트만 허용하려면 실행 정책을 AllSigned 또는 RemoteSigned로 변경합니다. RemoteSigned는 인터넷에서 다운로드한 스크립트에만 서명을 요구한다는 점이 AllSigned와 다릅니다.

Set-ExecutionPolicy AllSigned –Force

AllSigned 모드에서 서명되지 않은 스크립트를 실행하면 다음과 같은 오류가 표시됩니다.

File C:\script.ps1 cannot be loaded. The file script.ps1 is not digitally signed. You cannot run this script on the current system.

그룹 정책(GPO)을 통해 설정할 수도 있습니다. 컴퓨터 구성 -> 정책 -> 관리 템플릿 -> Windows 구성 요소 -> Windows PowerShell에서 스크립트 실행 켜기(Turn on Script Execution) 매개변수를 서명된 스크립트만 허용으로 변경하면 됩니다.

스크립트 서명 절차

이제 실제로 PowerShell 스크립트 파일에 서명해 보겠습니다. 먼저 현재 사용자의 로컬 인증서 저장소에서 코드 서명 인증서를 가져와야 합니다. 코드 서명에 사용할 수 있는 인증서 목록은 다음 명령으로 확인할 수 있습니다.

Get-ChildItem cert:\CurrentUser\my –CodeSigningCert

개인 인증서 저장소에서 첫 번째 인증서를 선택해 $cert 변수에 저장합니다.

$cert = (Get-ChildItem cert:\CurrentUser\my –CodeSigningCert)[0]

인증서를 신뢰할 수 있는 루트 인증서 저장소로 옮겼다면 아래 명령을 사용합니다.

$cert = (Get-ChildItem Cert:\LocalMachine\AuthRoot –CodeSigningCert)[0]

이제 이 인증서를 사용해 PS1 파일에 서명합니다.

Set-AuthenticodeSignature -Certificate $cert -FilePath C:\PS\testscript.ps1

다음과 같이 DnsName으로 앞서 만든 자체 서명 인증서를 지정할 수도 있습니다.

Set-AuthenticodeSignature C:\PS\test_script.ps1 @(gci Cert:\LocalMachine\AuthRoot -DnsName testPC1 -codesigning)[0]

참고: Set-AuthenticodeSignature cmdlet에는 타임스탬프 서비스 URL을 지정하는 특수 매개변수 TimestampServer가 있습니다. 이 매개변수를 비워 두면 인증서가 만료된 후 스크립트가 더 이상 실행되지 않습니다. 예시는 다음과 같습니다. -TimestampServer "https://timestamp.verisign.com/scripts/timstamp.dll"

서명 시 주의 사항

일반 SSL/TLS 인증서로 스크립트에 서명하려고 하면 다음과 같은 오류가 발생합니다.

Set-AuthenticodeSignature: Cannot sign code. The specified certificate is not suitable for code signing.

폴더 안의 모든 PowerShell 스크립트 파일을 한 번에 서명할 수도 있습니다.

Get-ChildItem c:\ps\*.ps1| Set-AuthenticodeSignature -Certificate $Cert

서명 결과 확인

Get-AuthenticodeSignature cmdlet을 사용하거나 PS1 파일 속성의 디지털 서명(Digital Signatures) 탭에서 서명이 올바르게 적용되었는지 확인할 수 있습니다.

Get-AuthenticodeSignature c:\ps\test_script.ps1 | ft -AutoSize

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

Set-AuthenticodeSignature 실행 중 UnknownError 경고가 나타난다면, 인증서가 사용자 개인 저장소에 있어 신뢰되지 않는 상태이기 때문입니다.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

이 경우 인증서를 신뢰할 수 있는 루트 인증 기관 저장소로 이동해야 합니다. (Windows 인증서 저장소를 주기적으로 점검하고 의심스러운 인증서가 있는지 확인하는 것도 잊지 마세요.)

Move-Item -Path $cert.PSPath -Destination "Cert:\LocalMachine\Root"

이후 PS1 파일의 서명을 검증하면 Valid 상태가 반환됩니다.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

서명 블록의 구조

Set-AuthenticodeSignature cmdlet으로 서명하면 PS1 텍스트 파일 끝에 디지털 서명 블록이 추가됩니다.

# SIG # Begin signature block
...........
...........
# SIG # End signature block

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

이 서명 블록에는 스크립트 해시가 포함되며, 이 해시는 프라이빗 키로 암호화되어 있습니다.

신뢰할 수 없는 게시자 경고 처리

서명된 스크립트를 처음 실행하면 다음과 같은 경고가 나타납니다.

Do you want to run software from this untrusted publisher?
File C:\PS\script.ps1 is published by CN=testPC1 and is not trusted on your system. Only run scripts from trusted publishers.

[A] Always run을 선택하면 이후 동일한 인증서로 서명된 스크립트를 실행할 때 경고가 더 이상 표시되지 않습니다.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

애초에 이 경고가 나타나지 않게 하려면 인증서를 신뢰할 수 있는 게시자(Trusted Publishers) 저장소에도 복사해야 합니다. 인증서 콘솔에서 복사-붙여넣기를 통해 인증서를 Trusted Publishers -> Certificates로 복사하세요.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

그러면 서명된 PowerShell 스크립트가 신뢰할 수 없는 게시자 알림 없이 실행됩니다.

팁: CA 루트 인증서와 스크립트 서명에 사용된 인증서는 반드시 신뢰되어야 합니다(그렇지 않으면 스크립트가 실행되지 않음). 도메인 환경에서는 GPO를 사용해 인증서를 일괄 배포할 수 있습니다. 컴퓨터 구성 -> 정책 -> Windows 설정 -> 보안 설정 -> 공개 키 정책의 신뢰할 수 있는 루트 인증 기간신뢰할 수 있는 게시자 섹션에 인증서를 배치하면 됩니다.

루트 인증서가 신뢰되지 않으면 스크립트 실행 시 다음 오류가 발생합니다.

A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.

서명 후 코드 변경 시 동작

서명된 PowerShell 스크립트의 코드를 수정하면 어떻게 될까요? 실행이 차단되며 스크립트 내용이 변경되었다는 알림이 표시됩니다.

File xx.ps1 cannot be loaded. The contents of file xx.ps1 might have been changed by an unauthorized user or process, because the hash of the file does not match the hash stored in the digital signature. The script cannot run on the specified system.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

Get-AuthenticodeSignature cmdlet으로 스크립트 서명을 검증해 보세요. 계산된 해시가 서명에 저장된 해시와 일치하지 않으면 HashMismatch 메시지가 나타납니다.

코드 서명 인증서로 PowerShell 스크립트(PS1)에 디지털 서명하는 방법

따라서 서명된 PS1 스크립트의 코드를 수정했다면 반드시 다시 서명해야 합니다.