😳

AppStream 2.0 Desktop Viewを起動してみてVDIとしての所感

13 min read

想定読者

  • VDI基盤の運営者
    • 複数人のユーザに対して、WindowsのRDP基盤を提供している方

AppStreamとは...の前に

アプリケーション仮想化

Citrix に代表されるように、
以前はOn-premにあった基幹系システム要件で、どうしても稼働しているアプリケーションのバージョンアップができない、
だけど、サポート期限が切れてしまった、といった延命措置のために利用されるケースが多かったのではないかと思います。

今はクラウドにシステム稼働基盤がリフト、リフトアンドシフトした関係で、
認証・認可を行ったユーザが取り扱うことのアプリケーションを制限したいといったような使い方の変化があるのかなと思います。

AppStream 2.0とは

1.0はないの?の疑問は、こちらのブログをご覧ください。
私も参考にさせていただいて、へぇと思った一人です。

参考1:AWS再入門ブログリレー Amazon AppStream 2.0 編
参考2:[アップデート] AppStream 2.0 にネイティブデスクトップエクスペリエンスのサポートが追加されました

2020年8月のサービスアップデートで何があったのか

以下のアナウンスが行われています。

Amazon AppStream 2.0 にネイティブデスクトップエクスペリエンスのサポートが追加されました

これにより、AWS の VDI サービスの単純に選択肢が増えました。
今までは、Amazon Workspace がNGだった場合は、
EC2でWindows Serverを作成して、RDP接続する形しか選択肢はありませんでした。

このサービスアップデートにより、複数人で利用する際のVDI基盤の選択肢が広がったのかなと思います。

ということで、少し自分でも所管を知りたく3時間程度で環境作ってみました。

システム管理者の観点で試してみた

前述で参考にさせていただいたクラスメソッドさんのブログでは触れられていなかった点について、
システム管理者の方が気にするだろうなという視点で見てみました。

CloudFormationで実験環境構築

CloudFormationで以下のテンプレートを使って作成しています。

<details><summary>テスト環境作成のCloudFormation</summary><div>

```
AWSTemplateFormatVersion: "2010-09-09"
Description:
VPC and Subnet Create

Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Project Name Prefix"
Parameters:
- PJPrefix
- Label:
default: "Network Configuration"
Parameters:
- VPCCIDR
- PublicSubnetCCIDR
- PublicSubnetDCIDR
- PrivateSubnetCCIDR
- PrivateSubnetDCIDR
ParameterLabels:
VPCCIDR:
default: "VPC CIDR"
PublicSubnetCCIDR:
default: "PublicSubnetC CIDR"
PublicSubnetDCIDR:
default: "PublicSubnetD CIDR"
PrivateSubnetCCIDR:
default: "PrivateSubnetC CIDR"
PrivateSubnetDCIDR:
default: "PrivateSubnetD CIDR"

------------------------------------------------------------#

Input Parameters

------------------------------------------------------------#

Parameters:
PJPrefix:
Type: String

VPCCIDR:
Type: String
Default: "10.0.0.0/16"

PublicSubnetCCIDR:
Type: String
Default: "10.0.1.0/24"

PublicSubnetDCIDR:
Type: String
Default: "10.0.2.0/24"

PrivateSubnetCCIDR:
Type: String
Default: "10.0.11.0/24"

PrivateSubnetDCIDR:
Type: String
Default: "10.0.12.0/24"

Resources:

------------------------------------------------------------#

VPC

------------------------------------------------------------#

VPC Create

VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: "true"
EnableDnsHostnames: "true"
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-vpc"

InternetGateway Create

InternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-igw"

IGW Attach

InternetGatewayAttachment:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC

------------------------------------------------------------#

Subnet

------------------------------------------------------------#

Public SubnetC Create

PublicSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PublicSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-subnet-c"

Public SubnetD Create

PublicSubnetD:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1d"
CidrBlock: !Ref PublicSubnetDCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-subnet-d"

Private SubnetC Create

PrivateSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PrivateSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-subnet-c"

Private SubnetD Create

PrivateSubnetD:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1d"
CidrBlock: !Ref PrivateSubnetDCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-subnet-d"

------------------------------------------------------------#

RouteTable

------------------------------------------------------------#

Public RouteTableC Create

PublicRouteTableC:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-route-c"

Public RouteTableD Create

PublicRouteTableD:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-route-d"

Private RouteTableC Create

PrivateRouteTableC:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-route-c"

Private RouteTableD Create

PrivateRouteTableD:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-route-d"

------------------------------------------------------------#

Routing

------------------------------------------------------------#

PublicRouteC Create

PublicRouteC:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PublicRouteTableC
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway

PublicRouteD Create

PublicRouteC:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PublicRouteTableD
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway

------------------------------------------------------------#

RouteTable Associate

------------------------------------------------------------#

PublicRouteTable Associate SubnetC

PublicSubnetARouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref PublicRouteTableC

PublicRouteTable Associate SubnetD

PublicSubnetARouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetD
RouteTableId: !Ref PublicRouteTableD

PrivateRouteTable Associate SubnetC

PrivateSubnetARouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref PrivateRouteTableC

PrivateRouteTable Associate SubnetD

PrivateSubnetCRouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetD
RouteTableId: !Ref PrivateRouteTableD

------------------------------------------------------------#

Output Parameters

------------------------------------------------------------#

Outputs:

VPC

VPC:
Value: !Ref VPC
Export:
Name: !Sub "${PJPrefix}-vpc"

VPCCIDR:
Value: !Ref VPCCIDR
Export:
Name: !Sub "${PJPrefix}-vpc-cidr"

Subnet

PublicSubnetC:
Value: !Ref PublicSubnetC
Export:
Name: !Sub "${PJPrefix}-public-subnet-c"

PublicSubnetCCIDR:
Value: !Ref PublicSubnetCCIDR
Export:
Name: !Sub "${PJPrefix}-public-subnet-c-cidr"

PublicSubnetD:
Value: !Ref PublicSubnetD
Export:
Name: !Sub "${PJPrefix}-public-subnet-d"

PublicSubnetDCIDR:
Value: !Ref PublicSubnetDCIDR
Export:
Name: !Sub "${PJPrefix}-public-subnet-d-cidr"

PrivateSubnetC:
Value: !Ref PrivateSubnetC
Export:
Name: !Sub "${PJPrefix}-private-subnet-c"

PrivateSubnetCCIDR:
Value: !Ref PrivateSubnetCCIDR
Export:
Name: !Sub "${PJPrefix}-private-subnet-c-cidr"

PrivateSubnetD:
Value: !Ref PrivateSubnetD
Export:
Name: !Sub "${PJPrefix}-private-subnet-d"

PrivateSubnetDCIDR:
Value: !Ref PrivateSubnetDCIDR
Export:
Name: !Sub "${PJPrefix}-private-subnet-d-cidr"

Route

PublicRouteTableC:
Value: !Ref PublicRouteTableC
Export:
Name: !Sub "${PJPrefix}-public-route-c"

PublicRouteTableD:
Value: !Ref PublicRouteTableD
Export:
Name: !Sub "${PJPrefix}-public-route-d"

PrivateRouteTableC:
Value: !Ref PrivateRouteTableC
Export:
Name: !Sub "${PJPrefix}-private-route-c"

PrivateRouteTableD:
Value: !Ref PrivateRouteTableD
Export:
Name: !Sub "${PJPrefix}-private-route-d"
```
</div></details>

使用可能なベースイメージについて

2020年11月3日時点では、Windows Server 2012 R2, 2016, 2019 の3種類のみとなっています。

OSベースイメージ

ClientOSに依存するアプリケーションを使っている方は、Amazon Workspace のみ選択肢となります。
参照: 自分の Windows デスクトップライセンスを使用する

デスクトップにあるImageAssistant(※)

ユーザプロファイルの保存について

AppStream 2.0 Desktop Viewは、インスタンス毎にユーザを紐付けるAmazon Workspaceと違い、
AutoScalling Policyで定義されているインスタンスをアクセスユーザで共有する仕様のため、
ユーザプロファイルは、インスタンス内部には保存できません。
一方で、S3 Bucket / Google Drive / OneDrive といった選択が可能となっています。

ユーザプロファイル

また、S3にユーザプロファイルを設定する場合、自動でS3 Bucketが作成されるうえに、
不意の削除を防ぐ、バケットポリシーも設定されていました。
(一通り検証終わって、削除するときにバケットポリシーの存在に気づきました。)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PreventAccidentalDeletionOfBucket",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:DeleteBucket",
            "Resource": "arn:aws:s3:::${S3-bucket-name}"
        }
    ]
}

ユーザ設定について

VDIサービスを使っているとシステム管理者の方が気にするであろうセキュリティの設定です。
以下の3点について設定可能です。

コピーアンドペーストの制限

双方向、あるいは単一方向(Local → Remote , Remote → Local )の設定となります。

コピーアンドペースト

ファイルのアップロード、ダウンロードの制限

双方向、あるいは単一方向(Local → Remote , Remote → Local )の設定となります。

ファイルの送受信

プリンタの制限

Localにprint許可をする設定となります。

引用: Get Started with Amazon AppStream 2.0: Set Up With Sample Applications

When they choose Print in the application, they can download a .pdf file that they can print to a local printer.
You can disable this option to prevent users from printing to a local device.

プリンタ

ログオフ

画面上部にAppStream 2.0のツールバーが表示され、そちらからログオフをする形となるため、
いつもどおりのログオフ手順と異なる点はユーザに伝える必要はあるかと思います。
事前に伝えないと、問い合わせに繋がるかなと...

電源オプション

ログオフ

ログオフ確認画面

その他

Image作成する際に、予めデスクトップに用意されているImageAssistを利用するのですが、
私の場合、DesktopViewを試すことを目的としていたので、
ショートアイコンを削除してしまい、実態がどこにいるのか焦りましたので、
同じ事態に陥る方のために2020年11月3日時点のパスを記載します。

C:\Program Files\Amazon\Photon\AppCatalogHelper\PhotonWindowsAppCatalogHelper.exe

所感

今回、まずはと思い3時間程度で、カスタムイメージの作成からFleetの作成までを行いました。

Amazon Workspaceの場合、前述の通り、ユーザをインスタンスに紐づけてしまうため、
全体のアカウント数に対して、アクティブユーザ数が少ない場合のVDIサービス基盤としての利用としてはいいのかなと思いました。

例えばシフト勤務などを行っている場合など、同時利用者数がアカウント数に対して少なくなると思いますので、
AppStrem 2.0 Desktop Viewを提供するといった形です。

また、50人程度の規模であれば、Amazon Cognitoで内部ユーザとして定義可能ですが、その場合 Photon Userと固定値になり、
ドメイン参加している場合は、個別のユーザ名になることも、事前に伝える必要があるかなと思います。

• 非ドメイン結合インスタンス: C:\Users\PhotonUser\My Files\Homeフォルダ
• ドメイン参加インスタンス: C:\Users\%username%\My Files\Homeフォルダ

引用: Amazon AppStream 2.0 管理ガイド

Discussion

ログインするとコメントできます