
こちらの記事は、以下の記事の続きとなります。
ここまでの構築方法は以下をご覧ください。
課題
弊社では、作業用端末として社員に iPad(第10世代)を配布しています。
普段の在宅ワークでは各自のパソコンから WorkSpaces にアクセスして作業してもらっています。
iPad でも WorkSpaces クライアントアプリケーションのインストールができるので、外出先からは iPad から WorkSpaces に接続して業務をしてもらおうと考えていました。
iPad 用の Magic Keyboard で操作することを想定していましたが、WorkSpaces にログインはできるけど、矢印キーが動作しない事象に遭遇しました。
原因
調べてみても原因や同じ事象は確認できず、正直、原因は不明です。
複数の端末で発生しているので、端末側の不具合とかではなさそうですが、同じような事象の報告はインターネットで確認できませんでした。
ただ、以下のように回避してひとまず矢印キーの操作ができるようになったのでよしとしています。
方法
結論から言うと、RDP で WorkSpaces に接続しています。
どうやら、PCoIP での接続に原因がありそうで、RDP で WorkSpaces に接続することで矢印キーの操作ができました。
以下を参考にしました。
RDP で WorkSpace に接続するにはどうすれば良いですか?
https://repost.aws/ja/knowledge-center/connect-workspace-rdp
ただ、WorkSpaces のあるサブネットは、プライベートサブネットのままにしておきたい要件もあり、AWS Client VPN も合わせて使うこととしました。
WorkSpaces で既に Directory Service を使用しているので、そのまま AWS Client VPN の承認にも使用できます。
結構これは嬉しくて、社員は普段使っているパスワードで AWS Client VPN に接続できます。
構成は以下のような感じです。

管理者側の手順
構成の準備としては、私がやったことは以下です。
WorkSpaces のセキュリティグループを変更
VPC 内からの RDP 通信を許可するように、WorkSpaces のセキュリティグループを変更します。
VPC CIDR を 10.0.0.0/16 として、以下の AWS CLI コマンドを実行しました。
# Get the ID of the security group for WorkSpaces
SECURITY_GROUP_ID=$(aws ec2 describe-security-groups \
--query "SecurityGroups[?ends_with(GroupName, '_workspacesMembers')].GroupId" \
--output text)
# Add an inbound rule to allow RDP traffic from VPC
aws ec2 authorize-security-group-ingress \
--group-id "$SECURITY_GROUP_ID" \
--protocol tcp \
--port 3389 \
--cidr 10.0.0.0/16
Route 53 ホストゾーンの作成
社員が RDP を使って WorkSpaces に接続するとき、WorkSpaces の IP アドレスを入力する必要があります。
IP アドレスは管理者(私)しか確認できず、いちいち社員に通知するのは面倒なので、自動的にユーザー ID に基づいたドメイン名を割り当てて運用することにしました。
- 以下の URL から Route 53 ホストゾーンを作成します。
https://us-east-1.console.aws.amazon.com/route53/v2/hostedzones#CreateHostedZone - 以下の設定で作成します。
- ドメイン名:user.workspaces
- タイプ:⦿ プライベートホストゾーン
- ホストゾーンに関連付ける VPC
- リージョン:アジアパシフィック (東京)
- VPC ID:WorkSpaces のある VPC
画像

Lambda ハンドラーの作成
Client VPN への接続と同時に実行したいプログラムなどを、Lambda ハンドラーで設定することができます。
WorkSpaces は起動していると結構高いので AutoStop モードで設定しています。
なので、Lambda ハンドラーでその都度起動することにします。
また、Lambda ハンドラーが WorkSpaces の IP アドレスを Route 53 ホストゾーンに登録してくれます。
- 以下の AWS CLI コマンドを実行し、Lambda 関数用の IAM ロールを作成します。
# Create IAM role
aws iam create-role \
--role-name LambdaRole-WorkSpaces \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}'
# Attach the IAM policy required for updating Route 53
aws iam attach-role-policy \
--role-name LambdaRole-WorkSpaces \
--policy-arn arn:aws:iam::aws:policy/AmazonRoute53FullAccess
# Attach the IAM policy required for updating WorkSpaces
aws iam attach-role-policy \
--role-name LambdaRole-WorkSpaces \
--policy-arn arn:aws:iam::aws:policy/AmazonWorkSpacesAdmin
# Attach the IAM policy required for logging
aws iam attach-role-policy \
--role-name LambdaRole-WorkSpaces \
--policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
- 以下の URL から Lambda 関数を作成します。
https://ap-northeast-1.console.aws.amazon.com/lambda/home?region=ap-northeast-1#/create/function - 以下の設定で作成します。
- 関数名:AWSClientVPN-ReadyWorkSpaces
※ AWSClientVPN- で始まる必要があります。† - ランタイム:Python 3.12
- 実行ロール:LambdaRole-WorkSpaces
- 関数名:AWSClientVPN-ReadyWorkSpaces
画像

- [設定] タブ > [一般設定] からタイムアウトの時間を1分に変更します。
画像

- Lambda 関数のコードを記入していきます。
ほとんど Chat GPT に書かせましたが以下です。
import boto3
def lambda_handler(event, context):
# Resource information
directory = '<Your Active Directory ID>'
hostedzone = '<Your Route 53 Hosted Zone ID>'
domain = 'user.workspaces'
# Get username from event
username = event.get('username')
if not username:
return {
"allow": True,
"error-msg-on-failed-posture-compliance": "Username not provided",
"posture-compliance-statuses": [],
"schema-version": "v2"
}
# Create WorkSpaces client
workspaces_client = boto3.client('workspaces')
# Get the user's WorkSpaces
response = workspaces_client.describe_workspaces(
DirectoryId=directory,
UserName=username
)
workspaces = response.get('Workspaces', [])
if not workspaces:
return {
"allow": True,
"error-msg-on-failed-posture-compliance": f'No WorkSpaces found for user {username}',
"posture-compliance-statuses": [],
"schema-version": "v2"
}
# Start WorkSpaces
workspace_id = workspaces[0]['WorkspaceId']
workspaces_client.start_workspaces(
StartWorkspaceRequests=[
{'WorkspaceId': workspace_id}
]
)
# Get the IP address of the WorkSpaces
workspace_ip = workspaces[0]['IpAddress']
# Create a Route 53 client
route53_client = boto3.client('route53')
# Create a subdomain name
subdomain = f"{username}.{domain}”
# Create a record
try:
route53_client.change_resource_record_sets(
HostedZoneId=hostedzone,
ChangeBatch={
'Changes': [
{
'Action': 'CREATE',
'ResourceRecordSet': {
'Name': subdomain,
'Type': 'A',
'TTL': 300,
'ResourceRecords': [{'Value': workspace_ip}]
}
}
]
}
)
except Exception as ex:
route53_client.change_resource_record_sets(
HostedZoneId=hostedzone,
ChangeBatch={
'Changes': [
{
'Action': 'UPSERT',
'ResourceRecordSet': {
'Name': subdomain,
'Type': 'A',
'TTL': 300,
'ResourceRecords': [{'Value': workspace_ip}]
}
}
]
}
)
return {
"allow": True,
"error-msg-on-failed-posture-compliance": f'Successfully started WorkSpaces for user {username}',
"posture-compliance-statuses": [],
"schema-version": "v2"
}
ACM に証明書を発行
Client VPN エンドポイントの作成にあたり、ACM の証明書が必要になります。
所有しているドメインがあれば一瞬で発行できますが、持っていない場合には、自身で証明書を発行して ACM にインポートする必要があります。
私の場合には、CloudShell で証明書を作成し、ACM にインポートしました。
- 以下の URL の手順 a で CloudShell を起動します。
https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/getting-started.html#launch-region-shell
- ナビゲーションバーで、 CloudShell アイコンを選択します。

- 以下の URL に記載のコマンドを実行し、証明書を発行しインポートします。
https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/client-auth-mutual-enable.html
$
git clone https://github.com/OpenVPN/easy-rsa.git$
cd easy-rsa/easyrsa3$
./easyrsa init-pki$
./easyrsa build-ca nopass$
./easyrsa --san=DNS:server build-server-full server nopass$
mkdir ~/custom_folder
/$
cp pki/ca.crt ~/custom_folder
/$
cp pki/issued/server.crt ~/custom_folder
/$
cp pki/private/server.key ~/custom_folder
/$
cd ~/custom_folder
/$
aws acm import-certificate --certificate fileb://server.crt --private-key fileb://server.key --certificate-chain fileb://ca.crt
Client VPN エンドポイントの作成と設定
- 以下の URL から Client VPN エンドポイントを作成します。
https://ap-northeast-1.console.aws.amazon.com/vpcconsole/home?region=ap-northeast-1#CreateClientVpnEndpoint: - 以下の設定で作成します。
- 名前タグ - オプション:client-vpn-for-remotework
- クライアント IPv4 CIDR:192.168.252.0/22
※ VPC CIDR との重複は NG† - サーバー証明書 ARN:ACM に証明書を発行 でインポートした証明書
- 認証オプション:☑️ ユーザーベースの認証を使用
- ユーザーベースの認証オプション:⦿ アクティブディレクトリ認証
- ディレクトリ ID:WorkSpaces で使用しているディレクトリ
- その他のパラメータ - オプション
- DNS サーバー 1 IP アドレス:VPC CIDR に +2 した IP アドレス
- VPC CIDR が 10.0.0.0/16 なら 10.0.0.2
- プライベートホストゾーンを使うのに VPC CIDR +2 を指定する必要があります。
- スプリットトンネルを有効化:有効
- 無効にすると iPad のすべてのトラフィックが AWS に流れるようになる?
- WorkSpaces への通信のみで十分なので有効にします。
- セルフサービスポータルを有効化:有効
- 社員自身で設定ファイルをダウンロードできるようになります。
- DNS サーバー 1 IP アドレス:VPC CIDR に +2 した IP アドレス
画像

- [ターゲットネットワークの関連付け] タブから、ターゲットネットワークを関連付けます。
- VPC:WorkSpaces のある VPC
- 関連付けるサブネットを選択:プライベートサブネットの1つ
画像

- [承認ルール] タブから、認証ルールを追加します。
- アクセスを有効にする送信先ネットワーク:0.0.0.0/0
- アクセス権を以下に付与する:⦿ アクセス権をすべてのユーザーに許可する
画像

- Client VPN エンドポイントが Available になるのを待ちます。
画像

ユーザー側の手順
そして、この構成に伴い、社員には以下の内容をお願いしました。
- iPad に OpenVPN クライアントをインストール
- セルフサービスポータルから設定ファイルをダウンロード
- URL:https://self-service.clientvpn.amazonaws.com/endpoints/<endpoint-id>
- OpenVPN クライアントに設定ファイルをインポート
- iPad に RD Client をインストール
- RD Client に PC を追加
- ホスト名:<user-id>.user.workspaces
社員が接続する際には、OpenVPN で Client VPN に接続した後に、RD Client で WorkSpaces に RDP に接続してもらうことにしました。
思ったより躓く方はおらず、展開もスムーズでした。
ひとまずこれで上手くいきそうなので、様子みようと思います。
どなたかの参考となれば幸いです。