iPad で Amazon WorkSpaces を使うと矢印キーが使えない

課題

弊社では、作業用端末としてスタッフに 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 に接続できます。
構成は以下のような感じです。

構成の準備としては以下です。

  1. Route 53 プライベートホストゾーン (user.workspaces) を作成
  2. Client VPN エンドポイントを作成
    • サーバ証明書は適当に取得していたドメインの証明書を使用
    • 認証はユーザー認証で既存の Directory Service を指定
    • 承認ルールは 0.0.0.0/0 を全てのユーザーに許可
      (そのうち WorkSpaces のサブネット CIDR に絞るかもしれません。)
    • ターゲットネットワークは適当なサブネットを指定
    • DNS は VPC CIDR +2 の IP アドレスを指定
      (プライベートホストゾーンを使うので)
  3. Lambda 関数 (AWSClientVPN-ReadyWorkSpaces) を作成
    • ユーザーの WorkSpaces を起動するため
    • ユーザーの WorkSpaces の IP アドレスにドメイン名を割り当てるため
    • それぞれに必要な権限を IAM ロールで付与
  4. Lambda ハンドラーを Client VPN エンドポイントに設定
  5. Client VPN エンドポイントから設定ファイルをダウンロードし社員に配布

WorkSpaces は起動していると結構高いので AutoStop モードで設定しています。
なので、Lambda ハンドラーでその都度起動することにします。
また、RDP を IP アドレスで指定する場合には、社員への展開が面倒なので、ドメイン名で管理することにしました。
Lambda ハンドラーが WorkSpaces の IP アドレスを Route 53 ホストゾーンに登録してくれます。
ほとんど Chat GPT に書かせましたが、Lambda 関数のコードは以下です。

AWSClientVPN-ReadyWorkSpaces のコード

import boto3

def lambda_handler(event, context):
    
    # リソース情報
    directory = '<ディレクトリ ID>'
    hostedzone = '<ホストゾーン ID>'
    domain = 'user.workspaces'
    
    # イベントからユーザー名を取得
    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"
        }
    
    # WorkSpaces クライアントを作成
    workspaces_client = boto3.client('workspaces')
    
    # ユーザーの 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"
        }
    
    # WorkSpaces を起動
    workspace_id = workspaces[0]['WorkspaceId']
    workspaces_client.start_workspaces(
        StartWorkspaceRequests=[
            {'WorkspaceId': workspace_id}
        ]
    )
    
    # WorkSpaces の IP アドレスを取得
    workspace_ip = workspaces[0]['IpAddress']
    
    # Route 53 クライアントを作成
    route53_client = boto3.client('route53')
    
    # サブドメイン名を作成
    subdomain = f"{username}.{domain}"
    
    # レコードを作成
    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"
    }

そして、この構成に伴い、社員には以下の内容をお願いしました。

  1. iPad に OpenVPN クライアントをインストール
  2. OpenVPN クライアントに設定ファイルをインポート(メールで配布しました。)
  3. iPad に RD Client をインストール
  4. RD Client に PC を追加
    • ホスト名:<ユーザー名>.user.workspaces

社員が接続する際には、OpenVPN で Client VPN に接続して、RD Client で WorkSpaces に RDP に接続してもらうことにしました。
思ったより躓く方はおらず、展開もスムーズでした。

ひとまずこれで上手くいきそうなので、様子みようと思います。
どなたかの参考となれば幸いです。

タイトルとURLをコピーしました