@@ -565,20 +565,29 @@ Resources:
565565
566566 snap start amazon-ssm-agent || systemctl start amazon-ssm-agent
567567
568- curl -fsSL https://get.docker.com | sh
568+ # Install Docker via GPG-signed apt repo
569+ install -m 0755 -d /etc/apt/keyrings
570+ curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
571+ chmod a+r /etc/apt/keyrings/docker.asc
572+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
573+ apt-get update
574+ apt-get install -y docker-ce docker-ce-cli containerd.io
569575 systemctl enable docker
570576 systemctl start docker
571577 usermod -aG docker ubuntu
572578
573579 sudo -u ubuntu bash << 'UBUNTU_SCRIPT'
574580 set -e
575581 cd ~
576- for i in {1..3}; do
577- if curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash; then
578- break
579- fi
582+ # Install NVM (download first, then execute)
583+ NVM_VERSION="v0.40.1"
584+ for i in 1 2 3; do
585+ curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/${!NVM_VERSION}/install.sh" -o /tmp/nvm-install.sh && break
586+ echo "NVM download attempt $i failed, retrying in 5s..."
580587 sleep 5
581588 done
589+ bash /tmp/nvm-install.sh
590+ rm -f /tmp/nvm-install.sh
582591 export NVM_DIR="$HOME/.nvm"
583592 [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
584593 nvm install 22
@@ -720,25 +729,58 @@ Resources:
720729 --region $REGION \
721730 --overwrite || echo "Failed to save token to SSM"
722731
732+ # Save instance info (non-secret metadata only)
723733 echo "$INSTANCE_ID" > /home/ubuntu/.openclaw/instance_id.txt
724734 echo "$REGION" > /home/ubuntu/.openclaw/region.txt
725- echo "$GATEWAY_TOKEN" > /home/ubuntu/.openclaw/gateway_token.txt
726735 chown ubuntu:ubuntu /home/ubuntu/.openclaw/*.txt
727736
737+ # Clear token from environment
738+ unset GATEWAY_TOKEN
739+
740+ # Create SSM access script (retrieves token from SSM at runtime — never stored on disk)
741+ cat > /home/ubuntu/ssm-portforward.sh << ' SSMEOF'
742+ # !/bin/bash
743+ IMDS_TOKEN=$(curl -s -X PUT http://169.254.169.254/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds : 21600")
744+ INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token : $IMDS_TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
745+ REGION=$(curl -s -H "X-aws-ec2-metadata-token : $IMDS_TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
746+ STACK_NAME=$(aws ec2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=aws:cloudformation:stack-name" --query "Tags[0].Value" --output text --region $REGION)
747+ TOKEN=$(aws ssm get-parameter --name "/openclaw/$STACK_NAME/gateway-token" --with-decryption --query Parameter.Value --output text --region $REGION)
748+
749+ echo "=========================================="
750+ echo "OpenClaw SSM Port Forwarding"
751+ echo "=========================================="
752+ echo ""
753+ echo "Run on your local computer:"
754+ echo ""
755+ echo "aws ssm start-session \\"
756+ echo " --target $INSTANCE_ID \\"
757+ echo " --region $REGION \\"
758+ echo " --document-name AWS-StartPortForwardingSession \\"
759+ echo " --parameters '{\"portNumber\":[\"18789\"],\"localPortNumber\":[\"18789\"]}'"
760+ echo ""
761+ echo "Then open in browser:"
762+ echo "http://localhost:18789/?token=$TOKEN"
763+ echo ""
764+ echo "=========================================="
765+ SSMEOF
766+ chmod +x /home/ubuntu/ssm-portforward.sh
767+ chown ubuntu:ubuntu /home/ubuntu/ssm-portforward.sh
768+
728769 apt-get install -y python3-pip 2>&1 | tee -a /var/log/openclaw-setup.log
729770 pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz 2>&1 | tee -a /var/log/openclaw-setup.log
730771
731772 CFN_SIGNAL=$(which cfn-signal 2>/dev/null || find /usr -name cfn-signal 2>/dev/null | head -1)
732- COMPLETE_URL="http://localhost:18789/? token=$GATEWAY_TOKEN "
773+ COMPLETE_MSG="OpenClaw ready. Retrieve token from SSM : aws ssm get-parameter --name /openclaw/$STACK_NAME/gateway- token --with-decryption --query Parameter.Value --output text --region $REGION "
733774
734775 if [ -n "$CFN_SIGNAL" ]; then
735- $CFN_SIGNAL -e 0 -d "$COMPLETE_URL " -r "OpenClaw ready" ' ${OpenClawWaitHandle}'
776+ $CFN_SIGNAL -e 0 -d "$COMPLETE_MSG " -r "OpenClaw ready" '${OpenClawWaitHandle}'
736777 else
737- SIGNAL_JSON="{\"Status\":\"SUCCESS\",\"Reason\":\"OpenClaw ready\",\"UniqueId\":\"openclaw\",\"Data\":\"$COMPLETE_URL \"}"
778+ SIGNAL_JSON="{\"Status\":\"SUCCESS\",\"Reason\":\"OpenClaw ready\",\"UniqueId\":\"openclaw\",\"Data\":\"$COMPLETE_MSG \"}"
738779 curl -X PUT -H 'Content-Type:' --data-binary "$SIGNAL_JSON" '${OpenClawWaitHandle}'
739780 fi
740781
741782 echo "OpenClaw multi-tenant installation complete!"
783+ echo "Token stored in SSM Parameter Store"
742784 Tags :
743785 - Key : Name
744786 Value : !Sub "${AWS::StackName}-gateway"
@@ -763,16 +805,8 @@ Outputs:
763805 aws ssm get-parameter --name "/openclaw/${AWS::StackName}/gateway-token" --region ${AWS::Region} --with-decryption --query 'Parameter.Value' --output text
764806
765807 Step4AccessURL :
766- Description : " STEP 4: Open this URL in browser"
767- Value : !Select
768- - 1
769- - !Split
770- - ' ":"'
771- - !Select
772- - 0
773- - !Split
774- - ' "}'
775- - !GetAtt OpenClawWaitCondition.Data
808+ Description : " STEP 4: Open in browser (replace <token> with value from Step 3)"
809+ Value : " http://localhost:18789/?token=<token>"
776810
777811 Step5StartChatting :
778812 Description : " STEP 5: Start using OpenClaw!"
0 commit comments