Microsoft MVP성태의 닷넷 이야기
글쓴 사람
홈페이지
첨부 파일
 

Azure VM/App Services(Web Apps)에 Let's Encrypt 무료 인증서 적용 방법

Azure 서비스에도 물론 Let's Encrypt 무료 인증서를 적용할 수 있습니다.

우선, 예전의 "Cloud Services (classic)" 유형의 웹 애플리케이션이라면 다음의 글에 따라 적용해야 합니다.

"Let's Encrypt" SSL 인증서를 Azure Cloud Services(classic)에 업데이트하는 방법
; https://www.sysnet.pe.kr/2/0/11054

주의할 것은, 3개월마다 저렇게 인증서 배포 작업을 해야 합니다.

반면, 가상 머신(VM)을 통해 웹 서비스를 하는 경우라면 일반적인 IIS 웹 서버와 동일하게 해당 VM에 RDP로 로그인한 후 다음의 글에 따라 설정하시면 됩니다.

"Let's Encrypt"에서 제공하는 무료 SSL 인증서를 IIS에 적용하는 방법 (2)
; https://www.sysnet.pe.kr/2/0/11483

이 경우, "Cloud Services (classic)"과는 다르게 VM 내부에 설정된 작업 스케줄러를 통해 인증서 갱신 작업을 자동화하기 때문에 사용자가 인증서 만료를 걱정할 필요가 없습니다.

마지막으로, Azure의 "App Services" 유형에 대해 "Let's Encrypt" 인증서를 적용하는 방법을 알아볼 텐데요. "Web App"의 경우 기본적으로 다음과 같은 도메인 이름을 사용할 수 있습니다.

http://[your_service_name].azurewebsites.net

마이크로소프트는 *.azurewebsites.net에 대한 인증서를 제공하므로 https 통신을 별도의 인증서 비용 없이 무료로 제공받게 됩니다. 따라서 여러분의 서비스가 다음과 같은 URL로 접근하는 것이 허용된다면 더 이상의 부가 작업은 필요 없습니다.

https://[your_service_name].azurewebsites.net




하지만 대개의 경우 자사의 고유한 도메인 이름이 있을 것이기 때문에 그것과 연결하게 될 것입니다.

Azure Web Apps(App Services)에 사용자 DNS를 지정하는 방법
; https://www.sysnet.pe.kr/2/0/11494

그다음, 저렇게 등록한 DNS에 대해 SSL 인증서를 설치해야 하는데요. 원래 App Services는 PaaS 유형의 서비스이기 때문에 "Cloud Services (classic)" 유형과 마찬가지로 인증서를 쉽게 적용할 수 없는 구조입니다. 그런데, "App Services" 유형에는 마이크로소프트가 특별히 Azure Site 확장 갤러리를 통해 외부 모듈들을 설치할 수 있는 기능을 제공하고 있기 때문에 Cloud services보다 더 쉽게 SSL 인증서를 관리하도록 만들 수 있습니다.

실제로 "Let's Encrypt" 인증서를 App Services에 연동할 수 있도록 해주는 '확장'이 이미 배포되고 있습니다. 따라서, Azure Portal에서 여러분의 App Service로 들어가 "개발 도구" 의 "확장"을 선택한 후,

app_services_lets_encrypt_1.png

"추가" 버튼을 누르면 다음 화면과 같이 "Azure Let's Encrypt"를 선택할 수 있습니다.

app_services_lets_encrypt_2.png

그다음, "고급 도구" 메뉴로 들어가 "이동"을 눌러,

app_services_lets_encrypt_3.png
(또는, 곧바로 https://[webapp_name].scm.azurewebsites.net 주소로 곧바로 이동할 수 있습니다.)

Kudu 화면의 "Site extensions"에서 "Azure Let's Encrypt"를 시작해 줍니다.

app_services_lets_encrypt_4.png

그럼 다음 화면과 같이 "Authentication Settings" 화면으로 넘어갑니다.

app_services_lets_encrypt_5.png

넣어야 하는 값이 좀 익숙하죠?

  • Tenant
  • SubscriptionId
  • ClientId
  • ClientSecret
  • ResourceGroupName
  • ServicePlanResourceGroupName
  • UseIPBasedSSL
  • SiteSlotName

이 중에서 Tenant, SubscriptionId는 Login-AzureRmAccount 명령어로 출력된 값을 사용하면 됩니다.

PS C:\> Login-AzureRmAccount

Account          : kevin2@jennifersoft.com
SubscriptionName : Pay-As-You-Go
SubscriptionId   : 4183b166-e0ee-493d-a7cb-addb11e39a0b
TenantId         : 1f4ab031-6c95-4c8e-800b-7f8c9094375e
Environment      : AzureCloud

그다음 ClientId, ClientSecret 값은 "Azure Let's Encrypt" 확장이 사용할 App 계정을 하나 만들어야 합니다.

Azure - PowerShell로 Access control(IAM)에 새로운 계정 만드는 방법
; https://www.sysnet.pe.kr/2/0/11479

C# - API를 사용해 Azure에 접근하는 방법
; https://www.sysnet.pe.kr/2/0/11480

New-AzureRmADServicePrincipal로 생성한 계정의 clientSecret, key 값을 구하는 방법
; https://www.sysnet.pe.kr/2/0/11501

위의 글에 따라 간략히 정리해 보면 다음과 같이 새로운 계정과 권한 부여를 하고,

PS> $plainText = "testpassword"
PS> $secureString = ConvertTo-SecureString $plainText -AsPlainText -Force
PS> $sp = New-AzureRmADServicePrincipal -DisplayName "NewUser1" -Password $secureString
PS> New-AzureRmRoleAssignment -ServicePrincipalName $sp.ApplicationId -RoleDefinitionName Contributor

PS> $sp | Select DisplayName, ApplicationId

DisplayName     ApplicationId
-----------     -------------
NewUser1     c5129bac-96f4-43fe-b5d7-dee8ce7ed2a0

출력된 ApplicationId == c5129bac-96f4-43fe-b5d7-dee8ce7ed2a0 값을 ClientId로 사용하면 됩니다. 그다음 ClientSecret 값은 "New-AzureRmADServicePrincipal로 생성한 계정의 clientSecret, key 값을 구하는 방법" 글에 따라 Azure Portal의 "App registrations(앱 등록)" 메뉴에서 등록해 구할 수 있습니다.

그 외 나머지 값은 상황에 따라 넣으면 됩니다.

ResourceGroupName: Web App(App Service)이 속한 리소스 그룹의 이름
ServicePlanResourceGroupName: App Service와 그것이 속한 Service Plan의 리소스 그룹이 다르다면 지정
                
UseIPBasedSSL: IP 기반 SSL을 쓸 일이 없으니.
SiteSlotName: 도움말 참조(https://github.com/ohadschn/letsencrypt-webapp-renewer)

설정을 완료한 다음, "Update Application Settings" 체크 박스를 누르고 "Next" 버튼을 눌러 진행합니다. 그럼, 다음의 화면으로 넘어갑니다.

app_services_lets_encrypt_6.png

Next를 한번 더 눌러서 진행하면, 다음과 같이 SSL 인증서의 이름으로 사용할 DNS를 묻는 단계로 갑니다.

app_services_lets_encrypt_7.png

Hostnames 목록에서 해당 도메인을 선택하고 이메일을 입력한 후 "Request and Install certificate" 버튼을 눌러 진행하면 인증서 발급 및 설치 절차가 완료됩니다. 이후로는 "https://jpublictest.sysnet.pe.kr" URL로 접속하면 정상적인 서비스가 되는 것을 확인할 수 있습니다.

참고로, 마지막 단계에서 "UseStaging" 옵션을 체크하고 "Request and Install certificate" 버튼을 누르는 것을 추천합니다. 이것은 테스트 용 인증서를 발급하고 설치까지 잘 진행되는지 확인하는 효과를 갖습니다. 이 작업의 의미는 아래에서 다룹니다.




Let's encrypt 확장 설정 시, ServicePlanResourceGroupName을 비워놓고 진행할 때 다음과 같은 오류가 발생했습니다.

The Service Plan Resource Group registered on the Web App in Azure in the ServerFarmId property 'myservice' does not match the value you entered here

이상하군요. "Optional"로 web app과 다른 리소스 그룹에 Service Plan이 설정된 경우에만 입력하라고 하는데 ResourceGroupName이 지정된 경우 무조건 지정해야 하는 것으로 보입니다. 따라서 ResourceGroupName과 같은 값을 넣고 진행하면 됩니다.




"Request and Install certificate" 버튼을 눌러 진행할 때 다음과 같은 오류가 발생하는 경우가 있다면?

Server Error in '/letsencrypt' Application.
Response status code does not indicate success: 403 (Forbidden).
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Net.Http.HttpRequestException: Response status code does not indicate success: 403 (Forbidden).

Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: 

[HttpRequestException: Response status code does not indicate success: 403 (Forbidden).]
   System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() +92620
   LetsEncrypt.Azure.Core.Services.WebAppCertificateService.Install(ICertificateInstallModel model) in J:\Projects\letsencrypt-siteextension\LetsEncrypt.SiteExtension.Core\Services\WebAppCertificateService.cs:56
   LetsEncrypt.Azure.Core.<RequestAndInstallInternalAsync>d__13.MoveNext() in J:\Projects\letsencrypt-siteextension\LetsEncrypt.SiteExtension.Core\CertificateManager.cs:187
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
   LetsEncrypt.SiteExtension.Controllers.<Install>d__7.MoveNext() +594
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
...[생략]...
   System.Web.CallHandlerExecutionStep.InvokeEndHandler(IAsyncResult ar) +152
   System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +125

App 계정의 권한이 "구독" 레벨에 지정하지 않았기 때문에 발생한 것입니다. 즉 '구독' 레벨이 아닌 그 하위의 리소스 레벨에 App 계정을 부여하면 저런 오류가 발생합니다.

사실 개인적으로 '왜 App Service의 SSL 인증서 설정에 구독 레벨의 권한 부여를 해야만 했을까?' 하는 의문이 듭니다. 게다가 아래의 글에 보면,

Response status code does not indicate success: 403 (Forbidden).
; https://github.com/sjkp/letsencrypt-siteextension/issues/141

구독 레벨은 아니어도 "Resource group" 레벨에 권한 부여를 해 성공한 사례를 써 놓고 있습니다. 심지어 답변은 "App Service"와 그것의 "App Service Plan"에만 부여해도 된다는 식으로 나와 있습니다. 암튼, 제가 해본 결과 반드시 "구독" 레벨로 권한 부여를 해야 403 Forbidden 오류가 발생하지 않습니다.




다음과 같은 오류를 만난다면?

Server Error in '/letsencrypt' Application.
The remote server returned an error: (429) Too Many Requests.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Net.WebException: The remote server returned an error: (429) Too Many Requests.

Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: 


[WebException: The remote server returned an error: (429) Too Many Requests.]
   System.Net.HttpWebRequest.GetResponse() +1399
   ACMESharp.AcmeClient.RequestHttpPost(Uri uri, Object message) in J:\Projects\letsencrypt-siteextension\ACMESharp\ACMESharp\ACMESharp\AcmeClient.cs:708

[AcmeWebException: Unexpected error
 +Response from server:
    + Code: 429
    + Content: {
  "type": "urn:acme:error:rateLimited",
  "detail": "Error creating new cert :: too many certificates already issued for exact set of domains: jpublictest.sysnet.pe.kr: see https://letsencrypt.org/docs/rate-limits/",
  "status": 429
}]
   ACMESharp.AcmeClient.RequestCertificate(String csrContent) in J:\Projects\letsencrypt-siteextension\ACMESharp\ACMESharp\ACMESharp\AcmeClient.cs:574
   LetsEncrypt.Azure.Core.Services.AcmeService.GetCertificate(AcmeClient client) in J:\Projects\letsencrypt-siteextension\LetsEncrypt.SiteExtension.Core\Services\AcmeService.cs:201
   LetsEncrypt.Azure.Core.Services.<RequestCertificate>d__5.MoveNext() in J:\Projects\letsencrypt-siteextension\LetsEncrypt.SiteExtension.Core\Services\AcmeService.cs:46
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
   LetsEncrypt.Azure.Core.<RequestInternalAsync>d__12.MoveNext() in J:\Projects\letsencrypt-siteextension\LetsEncrypt.SiteExtension.Core\CertificateManager.cs:173
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61
   LetsEncrypt.Azure.Core.<RequestAndInstallInternalAsync>d__13.MoveNext() in J:\Projects\letsencrypt-siteextension\LetsEncrypt.SiteExtension.Core\CertificateManager.cs:186
...[생략]...
   System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +125

"Request and Install certificate" 버튼을 눌러 진행하다가 오류를 5번 이상 겪었다면 위와 같은 오류로 넘어가게 됩니다. letsencrypt는 단일 도메인에 대해 한 주에 5개의 인증서만을 발급하는 제약이 있는데, 따라서 이미 5번의 인증서 발급을 모두 사용했기 때문에 urn:acme:error:rateLimited 오류가 발생하는 것입니다.

이 때문에라도 "Request and Install certificate" 버튼을 누르기 전 "UseStaging" 체크 박스를 설정하고 정상적으로 적용이 되는지 확인을 해보는 것이 좋습니다. 괜스레 저처럼 ^^ App 계정의 권한 부여 수준을 바꿔가면서 테스트하다가 오류가 5번을 넘기게 되면... 저런 제약을 만나게 됩니다. 어쩔 수 없습니다. 1주일 기다려야 합니다. ^^;




"Automated Installation" 단계에서 "Next" 버튼을 눌렀을 때 다음과 같은 오류가 발생할 수 있습니다.

azure_lets_encrypt_error_1.png

The ClientId registered under application settings 00000000-0000-0000-0000-000000000000 does not match the ClientId you entered here ...guid...


원인은 간단합니다.

Let's Encrypt: ClientID reqistered under application settings differs from what I entered?
; https://stackoverflow.com/questions/46728797/lets-encrypt-clientid-reqistered-under-application-settings-differs-from-what

"Update Application Settings" 체크 박스를 설정한 다음에 "Next" 버튼으로 진행해야 합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]





[최초 등록일: ]
[최종 수정일: 5/12/2018 ]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer@outlook.com

비밀번호

댓글 쓴 사람
 



2018-05-29 11시43분
Securing an Azure App Service Website under SSL in minutes with Let's Encrypt
; https://www.hanselman.com/blog/SecuringAnAzureAppServiceWebsiteUnderSSLInMinutesWithLetsEncrypt.aspx
정성태
2018-06-22 12시32분
정성태

... 16  17  18  19  20  21  22  23  24  25  26  27  28  [29]  30  ...
NoWriterDateCnt.TitleFile(s)
11516정성태5/9/20182128.NET Framework: 745. Azure runbook을 PowerShell 또는 C# 코드로 실행하는 방법파일 다운로드1
11515정성태6/8/20182495.NET Framework: 744. C# 6 - Expression bodied function
11514정성태5/3/20183947오류 유형: 466. Bitvise - Error in component session/transport/kexHandler [2]
11513정성태5/10/20184847.NET Framework: 743. C# 언어의 공변성과 반공변성 [5]파일 다운로드1
11512정성태5/3/20182215개발 환경 구성: 375. Azure runbook 실행 시 "Errors", "All Logs"에 오류 메시지가 출력되는 경우
11511정성태5/2/20182557개발 환경 구성: 374. Azure - Runbook 기능 소개
11510정성태4/30/20184190.NET Framework: 742. windbg로 확인하는 Finalizer를 가진 객체의 GC 과정파일 다운로드1
11509정성태4/28/20183663.NET Framework: 741. windbg로 확인하는 객체의 GC 여부
11508정성태4/23/20182896개발 환경 구성: 373. MSBuild를 이용해 프로젝트 배포 후 결과물을 zip 파일로 압축하는 방법파일 다운로드1
11507정성태9/29/20183113개발 환경 구성: 372. MSBuild - 빌드 전/후, 배포 전/후 실행하고 싶은 Task 정의
11506정성태6/27/20186017.NET Framework: 740. C#에서 enum을 boxing 없이 int로 변환하기 - 두 번째 이야기 [7]파일 다운로드1
11505정성태4/19/20182507개발 환경 구성: 371. Azure Web App 확장 예제 - Simple WebSite Extension
11504정성태4/19/20182653오류 유형: 465. Azure Web App 확장 - Extplorer File manager 적용 시 오류
11503정성태4/19/20182611오류 유형: 464. PowerShell - Start-Service 명령 오류 (Service 'xxx' cannot be started)
11502정성태5/12/20183653개발 환경 구성: 370. Azure VM/App Services(Web Apps)에 Let's Encrypt 무료 인증서 적용 방법 [2]
11501정성태4/17/20182401개발 환경 구성: 369. New-AzureRmADServicePrincipal로 생성한 계정의 clientSecret, key 값을 구하는 방법파일 다운로드1
11500정성태4/17/20182716개발 환경 구성: 368. PowerShell로 접근하는 Azure의 Access control 보안과 Azure Active Directory의 계정 관리 서비스
11499정성태4/17/20182290개발 환경 구성: 367. Azure - New-AzureRmADServicePrincipal / New-AzureRmRoleAssignment 명령어
11498정성태4/17/20182310개발 환경 구성: 366. Actvie Azure Directory의 사용자 유형 구분 - Guest/Member
11497정성태4/17/20182444개발 환경 구성: 365. Azure 리소스의 액세스 제어(Access control) 별로 사용자에게 권한을 할당하는 방법 [2]
11496정성태4/17/20182056개발 환경 구성: 364. Azure Portal에서 구독(Subscriptions) 메뉴가 보이지 않는 경우
11495정성태4/18/20182652개발 환경 구성: 363. Azure의 Access control 보안과 Azure Active Directory의 계정 관리 서비스
11494정성태4/16/20182425개발 환경 구성: 362. Azure Web Apps(App Services)에 사용자 DNS를 지정하는 방법
11493정성태4/16/20182416개발 환경 구성: 361. Azure Web App(App Service)의 HTTP/2 프로토콜 지원
11492정성태4/13/20182389개발 환경 구성: 360. Azure Active Directory의 사용자 도메인 지정 방법
11491정성태9/30/20192656개발 환경 구성: 359. Azure 가상 머신에 Web Application을 배포하는 방법
... 16  17  18  19  20  21  22  23  24  25  26  27  28  [29]  30  ...