はじめに
従来のAWS SSM(Systems Manager)によるノード管理は、AWS Organizationsを使用している場合であっても、稼働しているEC2インスタンス、ハイブリッド・サーバー、マルチクラウド環境で稼働しているサーバーは、各々のAWSアカウントのSSMのフリートマネージャー上でしか確認することができませんでした。
今回、2024年11月21日のAWS社からの発表により、AWS Organizationsを使用している場合、組織のAWSアカウントとリージョン内にある全てのマネージドインスタンス、アンマネージドインスタンスを一カ所で確認することが可能になったとの発表がありました。
まだクラウド環境を使用していないオンプレミス環境において、稼働しているLinuxサーバーの状態を一元管理する為には、Zabbixと呼ばれる監視ソフトウェアを使用されることが一般的かなと思います。
今回の発表によりCloud上にLinuxを移行した場合(一部オンプレミス環境にサーバーを残す場合含む)には、このAWS SSMのノード一元管理機能の使用が期待できるため、個人のAWS環境を使用して当該機能の検証を実施しました。本記事では、当該機能を使用する為の設定手順、及び、機能検証結果から判明した現時点での課題と思われるポイントをご紹介します。
機能検証
検証環境構成
使用するAWSアカウントは下記の3つになります。
- AWS Organizations Management Account
- 組織の管理者アカウントです。アカウントIDは「1xxxxxxx」としておきます。
- AWS Organizations Member Account (SSM Manager)
- 組織のメンバーアカウント、かつ、SSMの管理権限を委任されたアカウントです。
- アカウントIDは「2xxxxxxx」としておきます。
下記のドキュメントにも記載がありますが、今回検証する組織全体でのSSMのノード一元管理機能を有効にするためには、組織の管理者アカウントとは別のメンバーアカウントの中からSSMの管理者アカウントをアサインする必要がありますので、ご注意ください。
- AWS Organizations Member Account
- 組織のメンバーアカウントです。アカウントIDは「8xxxxxxx」としておきます。
各々のアカウントにつき、1つのプライベートEC2インスタンスを稼働させます。また、各々のVPCにはインターフェース・エンドポイントを設置し、PrivateLinkを使用してSSMとプライベート通信を行います。
また、AWS外のハイブリッド環境(自宅PC)で稼働しているVMWare上のLinuxも、組織の管理者アカウントの下でSSMのマネージドインスタンスとして管理しています。このAWSのEC2インスタンス以外のサーバーをSSMでマネージドインスタンスとして管理させるための設定手順については、下記の記事で纏めていますので、そちらを参照ください。
事前準備
各々のAWSアカウントにおいて、下記3つのCloudFormationのyamlファイルを使用して、スタックを作成しておきます。
- ネットワーク環境の作成
CreateNetwork-Stack.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Sample Script for Creating NetWork Stack (VPC,Public Subnet,Private Subnet,Internet Gateway,Nat Gateway,Route Table)
Parameters:
Azname:
Description: Set 1st az-name
Type: String
Default: ap-northeast-1a
AllowedValues:
- ap-northeast-1a
- ap-northeast-1c
- ap-northeast-1d
VPCCidrBlock:
Description: VPC Cidr Block
Type: String
Default: 10.0.0.0/16
PublicSubnetCidrBlock:
Description: Public Subnet Cidr Block for 1st az-name
Type: String
Default: 10.0.1.0/24
PrivateSubnetCidrBlock:
Description: Private Subnet Cidr Block for 1st az-name
Type: String
Default: 10.0.2.0/24
Resources:
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidrBlock
EnableDnsHostnames: 'true'
EnableDnsSupport: 'true'
Tags:
- Key: Name
Value: My-vpc
MyPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: !Ref PublicSubnetCidrBlock
AvailabilityZone: !Ref Azname
Tags:
- Key: Name
Value: My-Public-Subnet
DependsOn: MyVPC
MyPrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: !Ref PrivateSubnetCidrBlock
AvailabilityZone: !Ref Azname
Tags:
- Key: Name
Value: My-Private-Subnet
DependsOn: MyVPC
MyIGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: My-internet-gateway
DependsOn: MyVPC
MyIGWAttachToVPC:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref MyIGW
MyEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: My-Elastic-IP
DependsOn: MyIGWAttachToVPC
MyNGW:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt MyEIP.AllocationId
ConnectivityType: public
SubnetId: !Ref MyPublicSubnet
Tags:
- Key: Name
Value: My-NAT-Gateway
DependsOn: MyIGWAttachToVPC
MyPublicRtbl:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: My-Public-Rtbl
DependsOn: MyIGW
MyPublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: MyPublicRtbl
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyIGW
MyPublicSubnetRouteTblAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRtbl
SubnetId: !Ref MyPublicSubnet
MyPrivateRtbl:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: My-Private-Rtbl
MyPrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: MyPrivateRtbl
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref MyNGW
DependsOn: MyNGW
MyPrivateSubnetRouteTblAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRtbl
SubnetId: !Ref MyPrivateSubnet
MyPrivateSubnetSecGrp:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: My-Private-SecGrp
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: My-Private-SecGrp
Outputs:
MyStackVPCID:
Description: The ID of My VPC
Value: !Ref MyVPC
Export:
Name: !Sub "${AWS::StackName}--VPCId"
MyVPCCidrBlock:
Description: The CIDR block of My VPC
Value: !GetAtt MyVPC.CidrBlock
Export:
Name: !Sub "${AWS::StackName}--VPCCidrBlock"
MyStackPublicSubnetID:
Description: The ID of My Public Subnet for Azname
Value: !Ref MyPublicSubnet
Export:
Name: !Sub "${AWS::StackName}--PublicSubnetID"
MyStackPrivateSubnetID:
Description: The ID of My Private Subnet for Azname
Value: !Ref MyPrivateSubnet
Export:
Name: !Sub "${AWS::StackName}--PrivateSubnetID"
MyStackPrivateSubnetSecGrpID:
Description: The ID of My Private Security Group
Value: !Ref MyPrivateSubnetSecGrp
Export:
Name: !Sub "${AWS::StackName}--PrivateSubnetSecGrpID"
- プライベートEC2インスタンスの作成
CreatePrivateEC2-Stack.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Sample Script for Creating Private EC2 Instance
Parameters:
MyNetworkStackName:
Description: This stack name is already created Network Stack for provisioning Private EC2 Instance
Type: String
Default: Network-Stack
Resources:
MyKey:
Type: AWS::EC2::KeyPair
Properties:
KeyName: MyEC2Key
PublicKeyMaterial: '{{resolve:ssm:publickeymaterial}}'
Tags:
- Key: Name
Value: My-Key
MyPrivateInstance:
Type: AWS::EC2::Instance
Properties:
CreditSpecification:
CPUCredits: standard
InstanceType: t2.micro
KeyName: !Ref MyKey
ImageId: ami-094dc5cf74289dfbc
IamInstanceProfile: EC2Instance_Role
NetworkInterfaces:
- AssociatePublicIpAddress: "false"
DeviceIndex: "0"
SubnetId:
Fn::ImportValue:
!Sub "${MyNetworkStackName}--PrivateSubnetID"
GroupSet:
-
Fn::ImportValue:
!Sub "${MyNetworkStackName}--PrivateSubnetSecGrpID"
Tags:
- Key: Name
Value: Private-instance-03
Outputs:
MyPrivateInstanceIPaddr:
Description: My Private Instance's Private IP address for AzName
Value: !GetAtt MyPrivateInstance.PrivateIp
- SSMに対するインターフェースエンドポイントの作成
CreateSSMEndpoint-Stack.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Sample Script for Creating VPC Endpoint with SSM and SSM-Messages and EC2-Messages
Parameters:
MyNetworkStackName:
Description: This stack name is already created MyNetwork Stack for provisioning EC2 Instance
Type: String
Default: Network-Stack
Resources:
VPCEndpointSecGrp:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security Group for VPC Endpoint
VpcId:
Fn::ImportValue:
!Sub "${MyNetworkStackName}--VPCId"
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp:
Fn::ImportValue:
!Sub "${MyNetworkStackName}--VPCCidrBlock"
Tags:
- Key: Name
Value: VPCEndpoint-Security-Group
MySSMEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
ServiceName:
!Sub "com.amazonaws.${AWS::Region}.ssm"
PrivateDnsEnabled: true
VpcId:
Fn::ImportValue:
!Sub "${MyNetworkStackName}--VPCId"
SubnetIds:
- Fn::ImportValue:
!Sub "${MyNetworkStackName}--PrivateSubnetID"
SecurityGroupIds: # Must be a list of one or more
- !Ref VPCEndpointSecGrp
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action:
- "*"
Resource:
- "*"
DependsOn: VPCEndpointSecGrp
MySSMMSGEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
ServiceName:
!Sub "com.amazonaws.${AWS::Region}.ssmmessages"
PrivateDnsEnabled: true
VpcId:
Fn::ImportValue:
!Sub "${MyNetworkStackName}--VPCId"
SubnetIds:
- Fn::ImportValue:
!Sub "${MyNetworkStackName}--PrivateSubnetID"
SecurityGroupIds: # Must be a list of one or more
- !Ref VPCEndpointSecGrp
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action:
- "*"
Resource:
- "*"
DependsOn: VPCEndpointSecGrp
MySSMEC2MSGEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
ServiceName:
!Sub "com.amazonaws.${AWS::Region}.ec2messages"
PrivateDnsEnabled: true
VpcId:
Fn::ImportValue:
!Sub "${MyNetworkStackName}--VPCId"
SubnetIds:
- Fn::ImportValue:
!Sub "${MyNetworkStackName}--PrivateSubnetID"
SecurityGroupIds: # Must be a list of one or more
- !Ref VPCEndpointSecGrp
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action:
- "*"
Resource:
- "*"
DependsOn: VPCEndpointSecGrp
設定手順
下記ドキュメントの記載に従い設定していきます。
組織の管理アカウントでの設定作業
AWSのマネージドコンソールから「Systems Manager」のトップページに遷移し、下記図の赤枠部分の「使用開始」ボタンを押下します。
「使用開始」ボタンを押下後、下記画面に遷移します。ここで、SSMの管理を任せるアカウントID(2xxxxxx)を入力し、「確認」ボタンを押下します。
ちなみに、この画面で組織の管理アカウントIDを入力した場合は、先に述べた仕様の通り登録エラーになります。
SSM管理者登録が終わると、下記のように表示されます。
「管理者として登録されました」と言っている割には「委任された管理者なし」と表示されるというのはおかしいとは思いますが、一旦ここで組織の管理アカウントでの設定作業は終了です。
SSM管理者アカウントによる設定作業
SSM管理者アカウントでAWSマネージドコンソールにログオンし、「Systems Manager」の画面に遷移後、左側のメニューにある「設定」をクリックすると下記図のようになります。
AWSのドキュメントには「Systems Managerを有効にする」を選択するようにと書かれていますが、画面上既に有効になっており、「編集」というボタンが表示されています。ここもドキュメントには記載が見られない怪しいと思われる要素の1つです。先進めするため、「編集」ボタンを押下すると、下記図に遷移します。
ホームリージョンには、デフォルトで通常使用しているリージョン名が表示されます。リージョンは変更したり、他にも追加することが可能ですが、IAM Identity Centerを使用しており、そこでホームリージョンを指定している場合には、そのリージョン名と合せる必要があります。筆者の環境では、IAM Identity Centerでホームリージョンに東京リージョンを指定しているため、リージョンは「Custom」を選択し、ap-northeast-1以外のリージョンからチェックを外します。
上記図の概要に記載されている「管理アカウントを除く組織内のすべてのアカウントでSystems Managerを有効にします」という記述に関して、ここでの管理アカウントとは組織の管理アカウント、SSM管理アカウントのいずれの事を言っているのかな?と気にはなりましたが、とりあえず「送信」ボタンを押下します。すると下記画面に見られるように設定が開始されます。
組織の大きさによって設定時間は変わるようですが、設定が終わると下記画面のようになります。
内部的にはCloudFormationのスタックセットの実行を通して設定が行われていたようです。
設定結果確認
設定が終わったので、SSM管理アカウントのAWSマネージドコンソールにおいて「Systems Manager」の「ノードのインサイトを確認」に遷移すると、下記図のようになりました。
Amazon QuickSightのダッシュボードみたいで、見やすくて良いなと感じたのは束の間、マネージドノードが2ノードしかないのは何故という素朴な疑問が生じました。そこで、この2ノードの内訳を見るために、画面左側のメニューにある「ノードを詳しく見る」をクリックし、ノードの詳細を確認します。
表示されているノードのアカウントIDを見ると「2xxxxxx」と「8xxxxxx」の2種類のインスタンスしかなく、組織の管理アカウント「1xxxxx」配下で稼働しているEC2インスタンスとハイブリッド・サーバーが表示されていませんでした。
検証を通して判明した課題点
課題点1 組織のメンバーアカウント配下のインスタンスしか一元表示されない。
当該新機能は組織のアカウント全てにおけるEC2インスタンス、外部のハイブリッド・サーバー、マルチクラウド環境で稼働しているサーバーを一カ所で表示できるというものであるにも関わらず、組織の管理アカウント配下のEC2インスタンスやサーバーについては表示されません。AWSドキュメントにも「組織の管理アカウントについては一元管理対象外とする」なんて記載はどこにも書いてありません。
なお、組織の管理アカウントのAWSマネージドコンソールから「Systems Manager」→「ノードのインサイトを確認する」に遷移すると、下記のような表示がされました。
「Systems Manager統合エクスペリエンスは、組織の管理アカウントでは使用できません。組織全体のノードを管理する委任された管理者アカウントxxxxxxに切り替えてください。」と書かれてはいますが、あくまでもノードの一元管理画面を見ることは組織の管理アカウントではできないというだけだと考えましたが、正直謎です。。
仮にこの課題点1が仕様だった場合には、AWSドキュメントに明記してほしいですし、そういう仕様ではないというのであれば不具合だと思われるので、修正いただけると嬉しいです。
課題点2 当該機能の無効化は、現状AWSマネージドコンソールからは実施できない。
下記のAWSドキュメントでは、SSM管理者アカウントでAWSマネージドコンソールにログオン→「Systems Manager」に遷移→「設定」画面から「無効にする」ボタンを押下するとあります。
上図の「無効にする」ボタンを押下すると、下記の確認画面が表示されます。
なんと、「無効」と入力しても赤枠箇所の「Disable」ボタンが押下できないのです。。。。
これは明らかに不具合だと考えますが、以下の対応を行うことで、機能を無効にすることができました。
AWS CLIを使用した機能無効化手順
AWSのドキュメントには、組織の管理アカウントから、AWS CLIもしくはSDKを使用して、DeleteConfigurationManager APIをコールするようにと記載があります。ここでは、AWS CLIを使用して無効化を行いましたので、その手順を纏めました。無効化するためのコマンドは「aws ssm-quicksetup delete-configuration-manager」コマンドになります。
- AWS CLI V2の再インストール
- 最初インストールされていたCLIのレベルが低かったからか、コマンド実行時「aws quick-setupなんてコマンドは存在しない。」と言われてエラーになりました。ですので、こういった新機能関連のコマンドを実行される際には、先にCLIのレベルを上げられることをお奨めします。少なくともCLIのレベルが2.22.4であれば大丈夫です。
C:\Users\testuser>aws --version
aws-cli/2.22.4 Python/3.12.6 Windows/11 exe/AMD64
- ManagerArnの確認
- 「 aws ssm-quicksetup list-configuration-managers」コマンドを実行すれば、ManagerArnの確認が可能です。
ただ、初めてコマンドを実行する際にはコマンド権限がなく、下記のようなエラーになりました。
C:\Users\testuser>aws ssm-quicksetup list-configuration-managers
An error occurred (AccessDeniedException) when calling the ListConfigurationManagers operation: User: arn:aws:iam::1xxxxxxxxxx:user/ProdUser is not authorized to perform: ssm-quicksetup:ListConfigurationManagers on resource: arn:aws:ssm-quicksetup:ap-northeast-1:1xxxxxxxxxx:/listConfigurationManagers
そこで、以下のようなカスタマーポリシーを作成し、AWS CLI実行ユーザーのグループに当該ポリシーをアタッチします。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "ssm-quicksetup:*",
"Resource": "*"
}
]
}
再度コマンドを実行すると下記のような出力が得られ、ManagerArnを確認することができます。
C:\Users\kiyomasa>aws ssm-quicksetup list-configuration-managers
{
"ConfigurationManagersList": [
{
"ConfigurationDefinitionSummaries": [
{
"FirstClassParameters": {
"TargetOrganizationalUnits": "r-i2sa",
"TargetRegions": "ap-northeast-1"
},
"Id": "ixu9t",
"Type": "AWSQuickSetupType-SSM",
"TypeVersion": "1.0"
}
],
"Description": "",
"ManagerArn": "arn:aws:ssm-quicksetup:ap-northeast-1:1xxxxxxxx:configuration-manager/19fc7f33-8cd9-477e-8e52-7bfe2621ae99",
:
(略)
AWSドキュメントには、ManagerArnのフォーマットは「arn:aws:ssm-quicksetup:account-id:configuration-manager/AWSQuickSetupType-SSM」だと書かれています。もしかしたらAWS SDKを使用してAPI経由で確認する場合にはこのフォーマットが正しいのかもしれませんが、実際に「aws ssm-quicksetup delete-configuration-manager」コマンドで、--manager-arnオプションにこのフォーマットを指定するとエラーになるのでご注意ください。(account-idには組織の管理アカウントIDを指定したとしても。)
- 「aws ssm-quicksetup delete-configuration-manager」コマンドの実行
- 先の「aws ssm-quicksetup list-configuration-managers」の実行結果から確認できたManagerArnを指定し、コマンドを実行します。(1xxxxxxxxxは、組織の管理アカウントID)
C:\Users\testuser>aws ssm-quicksetup delete-configuration-manager --manager-arn arn:aws:ssm-quicksetup:ap-northeast-1:1xxxxxxxxx:configuration-manager/19fc7f33-8cd9-477e-8e52-7bfe2621ae99
C:\Users\testuser>
上記の様に空のプロンプトが返ってきたらコマンド実行は正常終了しています。この後、SSM管理アカウントでAWSマネージドコンソールにログオンし、「Systems Manager」→「ノードのインサイトを確認」に遷移すると、しばらく時間はかかりますが、下記図に見られるように当該機能が無事無効化されたことを確認できました。
機能無効化後の後始末
機能は無効化されましたが、SSMアカウントの登録等については引き続き残っています。これらを綺麗にする場合は、以下の手順を実施します。
組織の管理アカウントでの作業
Systems Manager Quick-Setup機能の管理委任者アカウント登録解除
AWSマネージドコンソールにおいて、「Systems Manager」→「高速セットアップ」に遷移し、委任された管理者アカウントの登録情報を削除します。
確認画面が表示されるので、「Confirm」ボタンを押下します。
下記のような画面に遷移できれば削除完了です。
Systems Manager Explorer機能の管理委任者アカウント登録解除
AWSマネージドコンソールにおいて、「Systems Manager」→「エクスプローラー」→「設定」に遷移し、委任された管理者アカウントの登録情報を削除します。
確認画面が表示されるので、「登録解除」ボタンを押下すれば解除完了です。
CloudFormationの管理委任者アカウント登録解除
AWSマネージドコンソールにおいて、「CloudFormation」→「StackSets」に遷移し、委任された管理者アカウントの登録を解除します。
確認画面が出るので、「登録解除」ボタンを押下すれば解除完了です。
AWS Resource Explorerの管理委任者アカウント登録解除
AWSマネージドコンソールにおいて、「AWS Resource Exploler」に遷移し、「信頼されたアクセスを無効にする」ボタンを押下し、委任された管理者アカウントの登録を解除します。
確認画面が出るので、「信頼されたアクセスを無効にする」ボタンを押下すれば、解除完了です。
おわりに
今回は、2024年11月21日にAWS社より発表されたAWS Systems Manager(SSM)の組織全体のノードを一元管理する新機能に関する検証を実施しました。残念ながら想定していた結果を得ることはできませんでしたが、検証結果から導き出された課題点がクリアになれば、今までにないSSMのノード管理を実現することが可能になる良き機能になると思いますので、何かのタイミングで修正いただけると嬉しいです。