[2019年度版] Let’s Encryptの証明書を使ってRD GatewayでWindowsサーバに接続

2019.04.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

しばたです。

先日は自己署名証明書を使ってRD Gatewayサーバーを構築する手順を紹介しましたが、今であれば自己署名証明書ではなくLet's Encryptを使って低コストでSSL証明書を利用することもできます。
本記事ではLet's Encryptの証明書を使ってRD Gatewayに設定する手順を紹介します。

前提条件

なんらかの独自ドメインを持ちRD Gatewayサーバーに対して適切なホスト名を割り当てていること

本記事ではRoute 53上にgateway01.shibata.classmethod.infoというホスト名を登録しこれを使うものとします。
(Route 53周りの設定については本記事では触れません)

RD Gatewayサーバーの構成と構築

RD Gatewayサーバーの構築手順については前回の記事の通りです。
前回の記事の延長として自己証明書をLet's Encryptの証明書切り替えるシナリオで進めていきます。

[2019年度版] 自己署名証明書のRD GatewayでWindowsサーバに接続

Posh-ACMEを使ったSSL証明書の作成

WindowsでLet's Encryptの証明書を発行するためのツールとしてはwin-acmeが有名ですが、本記事ではPowerShellモジュールとして提供されているPosh-ACMEを使います。

DNS検証(DNS-01)のための前準備

Let's Encryptで使われるACMEプロトコルではドメインの検証方法がいくつかありますが、本記事ではRD Gatewayで設定されるIISにあまり手を入れたくないのとDNSにRoute 53を使っているというのもありDNS検証(DNS-01)で行うことにします。
(実環境ではドメインの検証方法はその環境に応じてそれぞれ変わることになります)

Posh-ACMEでもプラグインの形でRoute 53でのDNS検証に対応しており、その手順が以下のドキュメントに記載されています。

このドキュメントではIAMユーザーおよびIAMロールを設定する手順が紹介されています。
本記事はEC2のRD Gatewayサーバー上で作業を行いますのでIAMロールを作成しEC2インスタンスにアタッチする方法を採用します。

1. IAMロールの作成とアタッチ

詳細は前掲のドキュメントを参照してほしいのですがPosh-ACMEでDNS検証をするためには以下のポリシーが要求されます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "route53:ListHostedZones"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "route53:GetHostedZone",
                "route53:ListResourceRecordSets",
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": "arn:aws:route53:::hostedzone/*",
            "Effect": "Allow"
        }
    ]
}

このポリシーを持つIAMロール(+インスタンスプロファイル)を生成するCloudFormationテンプレートを作りましたので、これを参考に生成したIAMロールをRD Gatewayサーバーにアタッチしておきます。

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  RoleName:
    Description: "Input Posh-ACME role name."
    Type: String
    Default: "PoshACMERole"
Resources:
  # IAM Role
  PoshACMERole:
    Type: AWS::IAM::Role
    Properties:
      RoleName:
        Fn::Sub: "${RoleName}"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: 'R53_Zone_Editor'
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - Effect: "Allow"
                Resource: "*"
                Action:
                  - "route53:ListHostedZones"
              - Effect: "Allow"
                Resource: "arn:aws:route53:::hostedzone/*"
                Action:
                  - "route53:GetHostedZone"
                  - "route53:ListResourceRecordSets"
                  - "route53:ChangeResourceRecordSets"
  # Instance Profile
  PoshACMERoleInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      InstanceProfileName:
        Fn::Sub: "${RoleName}"
      Path: "/"
      Roles:
        - Ref: PoshACMERole

2. AWSPowerShellモジュールのインストール

今回はEC2インスタンス上で作業するためAWSPowerShellモジュールはデフォルトでインストール済みですので追加の作業は不要です。
Posh-ACMEではDNS検証のための認証でプロファイルを使う場合のみAWSPowerShellモジュールが必要となります。

3. Posh-ACMEのインストール

ここから本題に入ります。
GD Gateway サーバーにログインし、Install-Moduleを使いPosh-ACMEモジュールをインストールします。

Install-Module -Name Posh-ACME -Scope CurrentUser

4. SSL証明書の生成

SSL証明書の生成はNew-PACertificateコマンドレットで行えます。
引数に証明書のホスト名や検証方式を選択します。
本記事では以下の引数を指定しています。

  • 第一引数 : ホスト名 (gateway01.shibata.classmethod.info)
  • -AcceptTOS : 利用規約に自動で同意する
  • -DnsPlugin Route53 : Route53によるDNS検証を行う
  • -PluginArgs @{R53UseIAMRole=$true} : IAMRoleを使ってDNS検証を行う
New-PACertificate "<Your RD Gateway server FQDN>" -AcceptTOS -DnsPlugin Route53 -PluginArgs @{R53UseIAMRole=$true}

実行後Eメールアドレスが登録されていない警告が表示されていますが、今回はこれを無視します。
本番環境での運用を行う場合は-Contactパラメーターを指定しメールアドレスの登録も一緒に行うと良いでしょう。

そしてGet-PACertificateコマンドレットで生成した証明書情報を確認すると以下の通りとなり、ユーザープロファイル配下のフォルダに各種ファイルが保存されていることがわかります。

Get-PACertificate | Format-List

5. SSL証明書のインポート

RD Gatewayでは秘密鍵を含む証明書をローカルコンピューター\個人にインポートしておく必要があります。
Import-PfxCertificateコマンドレットを使い生成した証明書(PFX形式の方)をインポートします。

# 生成した証明書情報を取得
$pacert = Get-PACertificate

# ローカルコンピューター\個人 に証明書をインポート
Import-PfxCertificate -FilePath $pacert.PfxFile -CertStoreLocation 'Cert:\LocalMachine\My\' -Password $pacert.PfxPass

6. SSL証明書をRD Gatewayに登録

証明書をインポートできれば後の手順は前回と変わりありません。
RemoteDesktopServicesモジュールをインポートしてSet-Itemで証明書を更新してください。
更新内容を反映させるにはサービスの再起動が必要となります。

# RDGatewayに証明書をセット
Import-Module RemoteDesktopServices
Set-Item -Path 'RDS:\GatewayServer\SSLCertificate\Thumbprint' -Value $pacert.Thumbprint

# サービス再起動
Stop-Service TSGateway
Start-Service TSGateway

GDゲートウェイマネージャーの画面からも証明書が更新されていることが確認できます。

クライアントからの接続確認

これでLet's Encryptの証明書でRD Gatewayサーバーを公開することができました。
クライアントからの接続は前回と変わりありません。

リモートデスクトップクライアントで設定するRDゲートウェイサーバーを更新したホスト名にすればOKです。

今回はちゃんと公開されている証明書ですのでクライアント側でのインポート作業は不要です。

証明書の更新

最後に証明書を更新する方法を解説して終わりにします。

生成した証明書を更新するにはSubmit-Renewalを呼び出すだけでOKです。
今回は最初に生成してからまだ間もないため-Forceパラメーターをつけて強制的に更新をかけておきます。

# 必要に応じて -Force パラメーターを付ける
$pacert = Submit-Renewal
$pacert

ちょっとわかりにくいですがこれで証明書は更新され新しくなっています。
あとは「5. SSL証明書のインポート」以降の手順を繰り返すだけでRD Gatewayの証明書を更新できます。

本記事では具体的な手順までは紹介しませんが、これくらいの内容であれば一連の手順をスクリプト化し、タスクスケジューラなどを使い定期実行させて証明書を自動更新させることも容易かと思います。