After setting up the Raspberry Pi, register it in Systems Manager and run commands from AWS

TOC

After setting up the Raspberry Pi, register it in Systems Manager and run commands from AWS

AWS Systems Manager can manage not only EC2 instances, but also servers in hybrid and multi-cloud environments.

https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-managedinstances.html

In this page, the Raspberry Pi 5 is registered with Systems Manager as if it were an on-premise server.
After registration, use the Systems Manager feature to run commands on the Raspberry Pi 5 from the AWS side.

Environment

Diagram of After setting up the Raspberry Pi, register it in Systems Manager and run commands from AWS.

Initial setup of the Raspberry Pi 5.
Specifically

  • Procurement of necessary supplies
  • OS Installation
  • Assembly and initial start-up

The OS to be installed on the Raspberry Pi will be the Raspberry Pi OS.
In addition, Macbook Air (M1, 2020) Sonoma 14.3.1 will be used for OS installation and other tasks.

Create an SSM Hybrid Activation to manage the Raspberry Pi with Systems Manager.
Install the SSM Agent on the Raspberry Pi while using the activation ID and code you prepared.

Once the Raspberry Pi can be managed by Systems Manager, we will use the functions of Systems Manager to execute commands on the Raspberry Pi.
In this case, for verification purposes, we will run the command to create a test file.

CloudFormation template files

In the above configuration, CloudFormation is used to build the AWS-side configuration.
The CloudFormation template is placed at the following URL

https://github.com/awstut-an-r/awstut-fa/tree/main/152

Raspberry Pi 5 first time setup

Procurement of necessary supplies

I have purchased the following items from Amazon.

Detail of Raspberry Pi 01.

Raspberry Pi 5

The first is the Raspberry Pi 5 itself.

This time, I purchased an 8GB type of memory.

SD card

The second is the SD card.

We chose a 128GB capacity.

Case

The third is a Raspberry Pi case.

Since it is undesirable to operate with the base exposed, and since we had heard that Raspberry Pi 5 generates a lot of heat, we prepared a case with a cooling fan.

Micro HDMI to HDMI Conversion Adapter

The fourth is a Micro HDMI to HDMI conversion adapter.

The port for video that the Raspberry Pi 5 has is Micro HDMI.
Since I did not have a cable for this port on hand, I purchased an adapter to convert it to a regular HDMI cable.

OS Installation

SD Card Preparation

The Raspberry Pi uses the SD card as storage.
So install the OS on the SD card.

First, remove the SD card from the packaging.

Detail of Raspberry Pi 03.

Attach the adapter to the micro SD card.

Detail of Raspberry Pi 04.

Recent Macbook Airs do not have a slot for an SD card, so a dock for a Macbook is used.

Connect the Macbook and SD card as follows

Detail of Raspberry Pi 05.

OS installation to SD card using Raspberry Pi Imager

Using a Macbook, install the OS on the SD card.
Use Raspberry Pi Imager for OS installation.

https://www.raspberrypi.com/software/

In order to use the Raspberry Pi Imager, the software must be installed on your Macbook.
Download the installer from the above page.

Detail of Raspberry Pi 06.

Double-click the downloaded installer and drag and drop the Raspberry Pi Imager into Applications.
This will install the Raspberry Pi Imager.

Detail of Raspberry Pi 07.

Launch the installed Raspberry Pi Imager.

Detail of Raspberry Pi 08.

Specify three items.

The items on the left relate to devices that boot the OS.

Detail of Raspberry Pi 09.

Select “Rasberry Pi 5.”

The middle item relates to the type of OS and the number of OS bits.

Detail of Raspberry Pi 10.

Select “Raspberry Pi OS (64-bit)”.

The items on the right relate to the SD card on which the OS is installed.

Detail of Raspberry Pi 11.

Select the SD card you just connected.

After completing the three selections, press “Next” and a page regarding additional configuration changes (Use OS customization?) will appear.

Detail of Raspberry Pi 12.

Press “Edit Settings.”

Three tabs will be displayed.
Each set as follows.

Detail of Raspberry Pi 13.
Detail of Raspberry Pi 14.
Detail of Raspberry Pi 15.

After clicking “Save,” the “Use OS customization?” page will appear again, so click “Yes” to confirm the setting.

The OS installation will then begin on the SD card.

Detail of Raspberry Pi 16.

After a short wait, the OS installation is complete.

Detail of Raspberry Pi 17.

Remove the SD card after this is displayed.

Case assembly

Remove the Raspberry Pi from the box.

Detail of Raspberry Pi 18.

Next, remove the case from the box.

Detail of Raspberry Pi 19.

The case is held in place by screws, but can be disassembled into two pieces when removed.

Screws and heat sinks are packaged inside the case.

Detail of Raspberry Pi 20.

Attach the four heat sinks to the Raspberry Pi.
The heat sinks are held in place with double-sided tape.

Attach the screws to the lower case.

Detail of Raspberry Pi 21.

These screws are used to secure the Raspberry Pi base to the case.

Thread this screw through the hole in the Raspberry Pi.

Detail of Raspberry Pi 22.

Further, screws are installed on top of the base to secure the case and base.

Detail of Raspberry Pi 23.

Connect the cable for the fan in the upper case to the base.

Detail of Raspberry Pi 24.

Note that the connection port is covered and must be removed.

Detail of Raspberry Pi 25.

Screw the case in place to complete the case assembly.

Initialization

Connect the SD card on which you just installed the OS to the Raspberry Pi.

Detail of Raspberry Pi 26.

In addition, connect cables.

Detail of Raspberry Pi 27.

Connect mouse/keyboard to USB port.
Connect the HDMI cable using the Micro HDMI conversion adapter.
Connect the power cable to the Type-C port.

Connect the power cable and the Rasberry Pi will automatically start up.

Detail of Raspberry Pi 28.

If it does not start, press the button on the side.

Register the Raspberry Pi with Systems Manager

To register your Raspberry Pi with Systems Manager, follow these steps

  1. Create a hybrid activation.
  2. Install SSM Agent on the Raspberry Pi while using the activation ID and code you have prepared.

Create a hybrid activation

Instructions on how to create a hybrid activation can be found on the following official AWS page

https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-managedinstances.html

Here are some pointers on creating a hybrid activation using CloudFormation.

Create IAM service role for SSM

As shown below, it is stated that an IAM role for SSM must be created in order to create a hybrid activation.

Non-EC2 (Amazon Elastic Compute Cloud) machines in a hybrid and multicloud environment require an AWS Identity and Access Management (IAM) service role to communicate with the AWS Systems Manager service. The role grants AWS Security Token Service (AWS STS) AssumeRole trust to the Systems Manager service.

Step 1: Create an IAM service role for a hybrid and multicloud environment
Resources:
  SSMServiceRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ssm.amazonaws.com
            Condition:
              StringEquals:
                aws:SourceAccount: !Ref AWS::AccountId
              ArnEquals:
                aws:SourceArn: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:*"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Code language: YAML (yaml)

IAM roles were created based on the above page.

The key point is that the AWS management policy AmazonSSMMManagedInstanceCore is attached to this role.

Create/delete activations using CloudFormation custom resources

When you create a hybrid activation, an activation ID and activation code will be returned.
These are used to install the SSM Agent on the Raspberry Pi.

It is possible to create/delete hybrid activations using the Management Console, AWS CLI, etc.
But CloudFormation does not provide the corresponding resource, so you cannot create activations directly.
So we can use a CloudFormation custom resource to call a Lambda function to create/delete activations when creating/deleting stacks.

Resources:
  CustomResource:
    Type: Custom::CustomResource
    Properties:
      ServiceToken: !GetAtt Function.Arn

  Function:
    Type: AWS::Lambda::Function
    Properties:
      Architectures:
        - !Ref Architecture
      Environment:
        Variables:
          PREFIX: !Ref Prefix
          REGION: !Ref AWS::Region
          SSM_SERVICE_ROLE: !Ref SSMServiceRole
      Code:
        ZipFile: |
          import boto3
          import cfnresponse
          import os

          prefix = os.environ['PREFIX']
          region = os.environ['REGION']
          ssm_service_role = os.environ['SSM_SERVICE_ROLE']

          CREATE = 'Create'
          DELETE = 'Delete'
          response_data = {}
          physical_resource_id = ''

          key_name_id = 'ActivationId'
          key_name_code = 'ActivationCode'

          ssm_client = boto3.client('ssm', region_name=region)

          def lambda_handler(event, context):
            print(event)

            try:
              if event['RequestType'] == CREATE:
                ssm_response = ssm_client.create_activation(
                  DefaultInstanceName=prefix,
                  IamRole=ssm_service_role
                )

                physical_resource_id = ssm_response[key_name_id]
                response_data[key_name_id] = ssm_response[key_name_id]
                response_data[key_name_code] = ssm_response[key_name_code]

              elif event['RequestType'] == DELETE:
                physical_resource_id = event['PhysicalResourceId']
                ssm_response = ssm_client.delete_activation(
                  ActivationId=physical_resource_id
                )

              cfnresponse.send(
                event=event,
                context=context,
                responseStatus=cfnresponse.SUCCESS,
                responseData=response_data,
                physicalResourceId=physical_resource_id
                )

            except Exception as e:
              print(e)
              cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
      FunctionName: !Sub "${Prefix}-function"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
      Timeout: !Ref Timeout

  FunctionRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: LambdaFunctionPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - iam:PassRole
                  - ssm:CreateActivation
                  - ssm:DeleteActivation
                Resource: "*"
Code language: YAML (yaml)

For basic information on CloudFormation custom resources, please see the following pages.

あわせて読みたい
Introduction to CloudFormation Custom Resources 【Configuration to check behavior of CloudFormation Custom resources】 One of the features of CloudFormation is custom resources. Custom resources enable you...

This time, we will execute a Lambda function in Python 3.12 runtime environment.

Check the contents of the code to be executed.
After creating the client object for boto3 SSM, execute create_activation method for stack creation and delete_activation method for stack deletion.
Create/delete hybrid activation respectively.

During stack creation, i.e. activation creation, the activation ID and activation code can be obtained.
Pass these as part of the responseData argument when executing the cfnresponse.send function.
This way you can set them to the Outputs of the CloudFormation stack and check the values after the stack is created.

In addition, the activation ID is specified in the physicalResourceId argument when executing the same function.
This is so that the activation ID can be referenced when deleting the stack, that is, when deleting an activation.

This idea was greatly inspired by the following pages.

https://dev.classmethod.jp/articles/on-premise-ubuntu-cloudfomation-aws-systems-manager-activation/

The beauty of this setting is that this value can be referenced even when deleting stacks.
The aforementioned responseData value is accessible from the CloudFormation template file side, but not from the custom resource side when deleting stacks.
The value of physicalResourceId, however, can be set during stack creation and referenced during stack deletion.
So by storing the activation ID in the physicalResourceId, this ID can be referenced when deleting the stack to delete the activation.

CloudFormation Stack Creation

Create a CloudFormation stack using the AWS CLI.
Place the above template file in any S3 bucket and then execute the following command

aws cloudformation create-stack \
--stack-name fa-152-01 \
--template-url https://[bucket-name].s3.[region].amazonaws.com/fa-152/fa-152-01.yaml \
--capabilities CAPABILITY_IAM
Code language: Bash (bash)

For more information on creating stacks, please see the following page.

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

Check the resources created.

Check the IAM role.

Detail of IAM 01.

Indeed, an IAM role has been created.
This IAM role is a service role for SSM.

Check the Lambda function.

Detail of Lambda 01.

The function is successfully created.

Check the execution log of this function.

Detail of Lambda 02.

The function is indeed executed.
This means that this function was automatically called by the CloudFormation custom resource when the stack was created.

If you look at the contents of the response in the log, you can see that Data is set to a hybrid activation ID and code.
In addition, we can see that the PhysicalResourceId value is the activation ID.

Since both data are set in Data, they can also be viewed in CloudFormation Outputs.

Detail of CloudFormation 01.

It does indeed show an activation ID and code.

Check Systems Manager.

Detail of SSM 01.

Indeed, a hybrid activation is created.

Thus, CloudFormation custom resources can be used to automatically create hybrid activations.

Install SSM Agent on Raspberry Pi

The following page shows how to install SSM Agent on a Raspberry Pi.

https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-install-managed-linux.html

This time, the following commands were executed on the Raspberry Pi.

sudo apt-get -y update
sudo apt-get -y upgrade
sudo apt-get -y install libc6:armhf
mkdir /tmp/ssm
curl https://amazon-ssm-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/debian_arm/ssm-setup-cli -o /tmp/ssm/ssm-setup-cli
sudo chmod +x /tmp/ssm/ssm-setup-cli
sudo /tmp/ssm/ssm-setup-cli -register -activation-code "[activation-code]" -activation-id "[activation-id]" -region "ap-northeast-1"
Code language: Bash (bash)

The bottom 4 lines are the commands from the above page and the top 4 lines are the commands I added.
This is because on my environment, a dependency error occurred and SSM Agent could not be installed successfully.

As the argument to the last command, specify the hybrid activation ID and code that you have just verified.

As for how to execute the above command, I did so by SSH into the Raspberry Pi.
If you have a mouse/keyboard directly connected to the Raspberry Pi, you can also execute the above command, but you will have to type the command manually.
So after checking the IP address set on the wireless LAN side of the Raspberry Pi (e.g. nmcli device show command), SSH to the same address and copy and paste the above command to execute. I decided to copy and paste the above command into SSH to the same address and execute it.

After the SSM Agent installation is successfully completed, the Agent will automatically start.

awstut@raspberrypi:~ $ sudo systemctl status amazon-ssm-agent
● amazon-ssm-agent.service - amazon-ssm-agent
      Loaded: loaded (/lib/systemd/system/amazon-ssm-agent.service; enabled; preset: enabled)
      Active: active (running) since Sun 2024-03-10 14:20:20 JST; 28s ago
    Main PID: 3709 (amazon-ssm-agen)
      Tasks: 19 (limit: 9250)
        CPU: 309ms
      CGroup: /system.slice/amazon-ssm-agent.service
              ├─3709 /usr/bin/amazon-ssm-agent
              └─3725 /usr/bin/ssm-agent-worker

Mar 10 14:20:20 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:20 INFO [amazon-ssm-agent] amazon-ssm-agent - v3.2.2303.0
Mar 10 14:20:20 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:20 INFO [amazon-ssm-agent] OS: linux, Arch: arm
Mar 10 14:20:20 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:20 INFO [amazon-ssm-agent] Starting Core Agent
Mar 10 14:20:20 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:20 INFO [CredentialRefresher] credentialRefresher has started
Mar 10 14:20:20 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:20 INFO [CredentialRefresher] Starting credentials refresher loop
Mar 10 14:20:20 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:20 INFO [CredentialRefresher] Credentials ready
Mar 10 14:20:20 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:20 INFO [CredentialRefresher] Next credential rotation will be in 29.9927887592 mi>
Mar 10 14:20:21 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:21 INFO [amazon-ssm-agent] [LongRunningWorkerContainer] [WorkerProvider] Worker ss>
Mar 10 14:20:21 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:21 INFO [amazon-ssm-agent] [LongRunningWorkerContainer] [WorkerProvider] Worker ss>
Mar 10 14:20:22 raspberrypi amazon-ssm-agent[3709]: 2024-03-10 14:20:21 INFO [amazon-ssm-agent] [LongRunningWorkerContainer] Monitor long running worke>
Code language: Bash (bash)

Check the AWS side again.

Check the Managed Node page in SSM Feet Manager.

Detail of SSM 02.

One Managed Node has indeed been added.
The Activation ID shows that it was indeed created by a CloudFormation custom resource earlier.

By installing the SSM Agent while using hybrid activation in this way, the Raspberry Pi can be registered with Systems Manager.

Using AWS Systems Manager to execute commands on the Raspberry Pi

Create SSM association

Up to the previous section, the Raspberry Pi is now ready to be managed by Systems Manager.
In this page, we will execute commands on the Raspberry Pi using the Systems Manager functions as an example of management.

Again, use CloudFormation to create SSM associations and execute them with Run Command.

Resources:
  RunShellScriptAssociation:
    Type: AWS::SSM::Association
    Properties:
      AssociationName: !Sub "${Prefix}-shellscript-association"
      Name: AWS-RunShellScript
      Parameters:
        commands:
          - "touch /tmp/test.txt"
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref NodeId
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

The contents of the SSM document AWS-RunShellScript to be executed against the target.

There are two points.

The first point is the script to run.
In this case, verification, we will use the touch command to create test.txt in the /tmp directory.

The second point is how to specify instances.
Specify the target instance with the Targets property.
Normally, the ID of the EC2 instance is specified in this property, but in this case we will specify the ID of the Managed Node assigned to the Raspberry Pi with hybrid activation enabled
In this case, it is “mi-0eb22a29750efc73c”.

CloudFormation Stack Creation

Again, we will use the AWS CLI to create the CloudFormation stack.
Place the above template file in any S3 bucket and then execute the following command

aws cloudformation create-stack \
--stack-name fa-152-02 \
--template-url https://[bucket-name].s3.[region].amazonaws.com/fa-152/fa-152-02.yaml
Code language: Bash (bash)

Check the resources created.

Check SSM State Manager.

Detail of SSM 03.
Detail of SSM 04.

Indeed, an association is created between the Managed Node, Raspberry Pi, and the SSM document AWS-RunShellScript.

Check SSM Run Command.

Detail of SSM 05.

Here you can see that the Run Command was executed against the Raspberry Pi and completed successfully.
This means that the Run Command was executed through State Manager.

Finally, access the Raspberry Pi and check the results of the Run Command execution.

awstut@raspberrypi:~ $ ls /tmp
ssh-XXXXXX1IKqpP
ssm
systemd-private-17099a81f2ff43059a22854d9f6f1f63-bluetooth.service-Z7slQf
systemd-private-17099a81f2ff43059a22854d9f6f1f63-ModemManager.service-SWnEDs
systemd-private-17099a81f2ff43059a22854d9f6f1f63-systemd-logind.service-44pZrv
systemd-private-17099a81f2ff43059a22854d9f6f1f63-systemd-timesyncd.service-kTxxXi
test.txt
tmp.iATINIcQGt
Code language: Bash (bash)

Indeed, test.txt is located in the /tmp directory of the Raspberry Pi.
We have confirmed that we were able to execute the command on the Raspberry Pi using the Systems Manager feature.

Summary

We have identified how to initially set up the Raspberry Pi 5.
Confirmed how to create/remove SSM Hybrid Activation by using CloudFormation custom resources.
Confirmed how to register with Systems Manager by installing SSM Agent while using activation on Raspberry Pi.
As an example of managing the Raspberry Pi with Systems Manager, we have identified how to execute commands on the Raspberry Pi using the Systems Manager features.

TOC