성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] How can I tell whether two programs...
[정성태] The case of the fail-fast crashes c...
[정성태] Creating Docker multi-arch images f...
[정성태] BinaryFormatter removed from .NET 9...
[정성태] Extending the Windows Shell Progres...
[우광현] 와..... 범위를 잡았으니 클라이언트가 해당 범위를 확인해본다...
[정성태] 딱히, 그것 이상으로 더 설명할 내용이 없습니다. 동적 포...
[정성태] If Windows 3.11 required a 32-bit p...
[정성태] What is a hard error, and what make...
[괴물신인] 질문작성자인데 이 글을 이제봤네요 ㄷㄷ 이 글처럼 타입별로 인...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Azure VM/App Services(Web Apps)에 Let's Encrypt 무료 인증서 적용 방법</h1> <p> Azure 서비스에도 물론 Let's Encrypt 무료 인증서를 적용할 수 있습니다.<br /> <br /> 우선, 예전의 "Cloud Services (classic)" 유형의 웹 애플리케이션이라면 다음의 글에 따라 적용해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > "Let's Encrypt" SSL 인증서를 Azure Cloud Services(classic)에 업데이트하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11054'>http://www.sysnet.pe.kr/2/0/11054</a> </pre> <br /> 주의할 것은, 3개월마다 저렇게 인증서 배포 작업을 해야 합니다.<br /> <br /> 반면, 가상 머신(VM)을 통해 웹 서비스를 하는 경우라면 일반적인 IIS 웹 서버와 동일하게 해당 VM에 RDP로 로그인한 후 다음의 글에 따라 설정하시면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > "Let's Encrypt"에서 제공하는 무료 SSL 인증서를 IIS에 적용하는 방법 (2) ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11483'>http://www.sysnet.pe.kr/2/0/11483</a> </pre> <br /> 이 경우, "Cloud Services (classic)"과는 다르게 VM 내부에 설정된 작업 스케줄러를 통해 인증서 갱신 작업을 자동화하기 때문에 사용자가 인증서 만료를 걱정할 필요가 없습니다.<br /> <br /> 마지막으로, Azure의 "App Services" 유형에 대해 "Let's Encrypt" 인증서를 적용하는 방법을 알아볼 텐데요. "Web App"의 경우 기본적으로 다음과 같은 도메인 이름을 사용할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > http://[your_service_name].azurewebsites.net </pre> <br /> 마이크로소프트는 *.azurewebsites.net에 대한 인증서를 제공하므로 https 통신을 별도의 인증서 비용 없이 무료로 제공받게 됩니다. 따라서 여러분의 서비스가 다음과 같은 URL로 접근하는 것이 허용된다면 더 이상의 부가 작업은 필요 없습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>https</span>://[your_service_name].azurewebsites.net </pre> <br /> <hr style='width: 50%' /><br /> <br /> 하지만 대개의 경우 자사의 고유한 도메인 이름이 있을 것이기 때문에 그것과 연결하게 될 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Azure Web Apps(App Services)에 사용자 DNS를 지정하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11494'>http://www.sysnet.pe.kr/2/0/11494</a> </pre> <br /> 그다음, 저렇게 등록한 DNS에 대해 SSL 인증서를 설치해야 하는데요. 원래 App Services는 PaaS 유형의 서비스이기 때문에 "Cloud Services (classic)" 유형과 마찬가지로 인증서를 쉽게 적용할 수 없는 구조입니다. 그런데, "App Services" 유형에는 마이크로소프트가 특별히 Azure Site 확장 갤러리를 통해 외부 모듈들을 설치할 수 있는 기능을 제공하고 있기 때문에 Cloud services보다 더 쉽게 SSL 인증서를 관리하도록 만들 수 있습니다.<br /> <br /> 실제로 "Let's Encrypt" 인증서를 App Services에 연동할 수 있도록 해주는 '확장'이 이미 배포되고 있습니다. 따라서, Azure Portal에서 여러분의 App Service로 들어가 "개발 도구" 의 "확장"을 선택한 후,<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='app_services_lets_encrypt_1.png' src='/SysWebRes/bbs/app_services_lets_encrypt_1.png' /><br /> <br /> "추가" 버튼을 누르면 다음 화면과 같이 "Azure Let's Encrypt"를 선택할 수 있습니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='app_services_lets_encrypt_2.png' src='/SysWebRes/bbs/app_services_lets_encrypt_2.png' /><br /> <br /> 그다음, "고급 도구" 메뉴로 들어가 "이동"을 눌러,<br /> <br /> <img alt='app_services_lets_encrypt_3.png' src='/SysWebRes/bbs/app_services_lets_encrypt_3.png' /><br /> (또는, 곧바로 https://[webapp_name].scm.azurewebsites.net 주소로 곧바로 이동할 수 있습니다.)<br /> <br /> Kudu 화면의 "Site extensions"에서 "Azure Let's Encrypt"를 시작해 줍니다. <br /> <br /> <img alt='app_services_lets_encrypt_4.png' src='/SysWebRes/bbs/app_services_lets_encrypt_4.png' /><br /> <br /> 그럼 다음 화면과 같이 "Authentication Settings" 화면으로 넘어갑니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='app_services_lets_encrypt_5.png' src='/SysWebRes/bbs/app_services_lets_encrypt_5.png' /><br /> <br /> 넣어야 하는 값이 좀 익숙하죠?<br /> <br /> <ul> <li>Tenant</li> <li>SubscriptionId</li> <li>ClientId</li> <li>ClientSecret</li> <li>ResourceGroupName</li> <li>ServicePlanResourceGroupName</li> <li>UseIPBasedSSL</li> <li>SiteSlotName</li> </ul> <br /> <a name='tenantid'></a> 이 중에서 Tenant, SubscriptionId는 <a target='tab' href='http://www.sysnet.pe.kr/2/0/11500'>Login-AzureRmAccount</a> 명령어로 출력된 값을 사용하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > PS C:\> Login-AzureRmAccount Account : kevin2@jennifersoft.com SubscriptionName : Pay-As-You-Go <span style='color: blue; font-weight: bold'>SubscriptionId : 4183b166-e0ee-493d-a7cb-addb11e39a0b TenantId : 1f4ab031-6c95-4c8e-800b-7f8c9094375e</span> Environment : AzureCloud </pre> <br /> 그다음 ClientId, ClientSecret 값은 "Azure Let's Encrypt" 확장이 사용할 App 계정을 하나 만들어야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Azure - PowerShell로 Access control(IAM)에 새로운 계정 만드는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11479'>http://www.sysnet.pe.kr/2/0/11479</a> C# - API를 사용해 Azure에 접근하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11480'>http://www.sysnet.pe.kr/2/0/11480</a> New-AzureRmADServicePrincipal로 생성한 계정의 clientSecret, key 값을 구하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11501'>http://www.sysnet.pe.kr/2/0/11501</a> </pre> <br /> 위의 글에 따라 간략히 정리해 보면 다음과 같이 새로운 계정과 권한 부여를 하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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 <span style='color: blue; font-weight: bold'>c5129bac-96f4-43fe-b5d7-dee8ce7ed2a0</span> </pre> <br /> 출력된 ApplicationId == c5129bac-96f4-43fe-b5d7-dee8ce7ed2a0 값을 ClientId로 사용하면 됩니다. 그다음 ClientSecret 값은 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/11501'>New-AzureRmADServicePrincipal로 생성한 계정의 clientSecret, key 값을 구하는 방법</a>" 글에 따라 Azure Portal의 "App registrations(앱 등록)" 메뉴에서 등록해 구할 수 있습니다.<br /> <br /> 그 외 나머지 값은 상황에 따라 넣으면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ResourceGroupName: Web App(App Service)이 속한 리소스 그룹의 이름 ServicePlanResourceGroupName: App Service와 그것이 속한 Service Plan의 리소스 그룹이 다르다면 지정 UseIPBasedSSL: IP 기반 SSL을 쓸 일이 없으니. SiteSlotName: 도움말 참조(https://github.com/ohadschn/letsencrypt-webapp-renewer) </pre> <br /> 설정을 완료한 다음, "Update Application Settings" 체크 박스를 누르고 "Next" 버튼을 눌러 진행합니다. 그럼, 다음의 화면으로 넘어갑니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='app_services_lets_encrypt_6.png' src='/SysWebRes/bbs/app_services_lets_encrypt_6.png' /><br /> <br /> Next를 한번 더 눌러서 진행하면, 다음과 같이 SSL 인증서의 이름으로 사용할 DNS를 묻는 단계로 갑니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='app_services_lets_encrypt_7.png' src='/SysWebRes/bbs/app_services_lets_encrypt_7.png' /><br /> <br /> Hostnames 목록에서 해당 도메인을 선택하고 이메일을 입력한 후 "Request and Install certificate" 버튼을 눌러 진행하면 인증서 발급 및 설치 절차가 완료됩니다. 이후로는 "<a target='tab' href='https://jpublictest.sysnet.pe.kr'>https://jpublictest.sysnet.pe.kr</a>" URL로 접속하면 정상적인 서비스가 되는 것을 확인할 수 있습니다.<br /> <br /> 참고로, 마지막 단계에서 "UseStaging" 옵션을 체크하고 "Request and Install certificate" 버튼을 누르는 것을 추천합니다. 이것은 테스트용 인증서를 발급하고 설치까지 잘 진행되는지 확인하는 효과를 갖습니다. 이 작업의 의미는 아래에서 다룹니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> Let's encrypt 확장 설정 시, ServicePlanResourceGroupName을 비워놓고 진행할 때 다음과 같은 오류가 발생했습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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 </pre> <br /> 이상하군요. "Optional"로 web app과 다른 리소스 그룹에 Service Plan이 설정된 경우에만 입력하라고 하는데 ResourceGroupName이 지정된 경우 무조건 지정해야 하는 것으로 보입니다. 따라서 ResourceGroupName과 같은 값을 넣고 진행하면 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> "Request and Install certificate" 버튼을 눌러 진행할 때 다음과 같은 오류가 발생하는 경우가 있다면?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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 </pre> <br /> <a target='tab' href='http://www.sysnet.pe.kr/2/0/11500'>App 계정의 권한이 "구독" 레벨</a>에 지정하지 않았기 때문에 발생한 것입니다. 즉 '구독' 레벨이 아닌 그 하위의 리소스 레벨에 App 계정을 부여하면 저런 오류가 발생합니다.<br /> <br /> 사실 개인적으로 '왜 App Service의 SSL 인증서 설정에 구독 레벨의 권한 부여를 해야만 했을까?' 하는 의문이 듭니다. 게다가 아래의 글에 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Response status code does not indicate success: 403 (Forbidden). ; <a target='tab' href='https://github.com/sjkp/letsencrypt-siteextension/issues/141'>https://github.com/sjkp/letsencrypt-siteextension/issues/141</a> </pre> <br /> 구독 레벨은 아니어도 "Resource group" 레벨에 권한 부여를 해 성공한 사례를 써 놓고 있습니다. 심지어 답변은 "App Service"와 그것의 "App Service Plan"에만 부여해도 된다는 식으로 나와 있습니다. 암튼, 제가 해본 결과 반드시 "구독" 레벨로 권한 부여를 해야 403 Forbidden 오류가 발생하지 않습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 다음과 같은 오류를 만난다면?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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 </pre> <br /> "Request and Install certificate" 버튼을 눌러 진행하다가 오류를 5번 이상 겪었다면 위와 같은 오류로 넘어가게 됩니다. letsencrypt는 단일 도메인에 대해 한 주에 5개의 인증서만을 발급하는 제약이 있는데, 따라서 이미 5번의 인증서 발급을 모두 사용했기 때문에 urn:acme:error:rateLimited 오류가 발생하는 것입니다.<br /> <br /> 이 때문에라도 "Request and Install certificate" 버튼을 누르기 전 "UseStaging" 체크 박스를 설정하고 정상적으로 적용이 되는지 확인을 해보는 것이 좋습니다. 괜스레 저처럼 ^^ App 계정의 권한 부여 수준을 바꿔가면서 테스트하다가 오류가 5번을 넘기게 되면... 저런 제약을 만나게 됩니다. 어쩔 수 없습니다. 1주일 기다려야 합니다. ^^;<br /> <br /> <hr style='width: 50%' /><br /> <br /> "Automated Installation" 단계에서 "Next" 버튼을 눌렀을 때 다음과 같은 오류가 발생할 수 있습니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='azure_lets_encrypt_error_1.png' src='/SysWebRes/bbs/azure_lets_encrypt_error_1.png' /><br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> The ClientId registered under application settings 00000000-0000-0000-0000-000000000000 does not match the ClientId you entered here ...guid...<br /> </div><br /> <br /> 원인은 간단합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Let's Encrypt: ClientID reqistered under application settings differs from what I entered? ; <a target='tab' href='https://stackoverflow.com/questions/46728797/lets-encrypt-clientid-reqistered-under-application-settings-differs-from-what'>https://stackoverflow.com/questions/46728797/lets-encrypt-clientid-reqistered-under-application-settings-differs-from-what</a> </pre> <br /> "Update Application Settings" 체크 박스를 설정한 다음에 "Next" 버튼으로 진행해야 합니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1860
(왼쪽의 숫자를 입력해야 합니다.)