AWS Setup
This guide walks you through creating an IAM user with the necessary permissions to deploy Serverless CMS.
On This Page
Step 1: Create IAM User
- Log in to the AWS Console
- Navigate to IAM → Users
- Click Create user
- Enter username:
serverless-cms-deployer - Click Next
Step 2: Attach Required Policies
The deployment user needs permissions to create and manage AWS services. You have two options:
Option A: Use Managed Policies (Simpler)
Attach these AWS managed policies to the user:
- AmazonS3FullAccess - For website hosting and storage
- AmazonDynamoDBFullAccess - For Content_Store database
- AWSLambda_FullAccess - For Lambda functions
- AmazonAPIGatewayAdministrator - For CMS_API and Public_API
- AmazonCognitoPowerUser - For user authentication
- CloudFrontFullAccess - For CDN distribution
- AmazonRoute53FullAccess - For DNS management
- AWSCertificateManagerFullAccess - For HTTPS certificates
- IAMFullAccess - For creating service roles
Option B: Create Custom Policy (Recommended for Production)
Create a custom policy with least-privilege permissions:
- In IAM, go to Policies → Create policy
- Switch to the JSON tab
- Paste the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Management",
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:DeleteBucket",
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:GetBucketPolicy",
"s3:PutBucketPolicy",
"s3:DeleteBucketPolicy",
"s3:GetBucketVersioning",
"s3:PutBucketVersioning",
"s3:GetBucketWebsite",
"s3:PutBucketWebsite",
"s3:DeleteBucketWebsite",
"s3:GetBucketCORS",
"s3:PutBucketCORS",
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucketVersions",
"s3:GetObjectVersion",
"s3:DeleteObjectVersion"
],
"Resource": [
"arn:aws:s3:::*serverless-cms*",
"arn:aws:s3:::*serverless-cms*/*"
]
},
{
"Sid": "DynamoDBManagement",
"Effect": "Allow",
"Action": [
"dynamodb:CreateTable",
"dynamodb:DeleteTable",
"dynamodb:DescribeTable",
"dynamodb:UpdateTable",
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:DeleteItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:BatchWriteItem",
"dynamodb:BatchGetItem",
"dynamodb:UpdateTimeToLive",
"dynamodb:DescribeTimeToLive"
],
"Resource": "arn:aws:dynamodb:eu-west-2:*:table/*serverless-cms*"
},
{
"Sid": "LambdaManagement",
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:DeleteFunction",
"lambda:GetFunction",
"lambda:GetFunctionConfiguration",
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"lambda:ListFunctions",
"lambda:PublishVersion",
"lambda:GetPolicy",
"lambda:AddPermission",
"lambda:RemovePermission",
"lambda:TagResource",
"lambda:InvokeFunction"
],
"Resource": "arn:aws:lambda:eu-west-2:*:function:*serverless-cms*"
},
{
"Sid": "APIGatewayManagement",
"Effect": "Allow",
"Action": ["apigateway:*"],
"Resource": "arn:aws:apigateway:eu-west-2::/*"
},
{
"Sid": "CognitoManagement",
"Effect": "Allow",
"Action": [
"cognito-idp:CreateUserPool",
"cognito-idp:DeleteUserPool",
"cognito-idp:DescribeUserPool",
"cognito-idp:UpdateUserPool",
"cognito-idp:CreateUserPoolClient",
"cognito-idp:DeleteUserPoolClient",
"cognito-idp:DescribeUserPoolClient",
"cognito-idp:UpdateUserPoolClient",
"cognito-idp:CreateGroup",
"cognito-idp:DeleteGroup",
"cognito-idp:AdminCreateUser",
"cognito-idp:AdminDeleteUser",
"cognito-idp:AdminAddUserToGroup",
"cognito-idp:ListUsers",
"cognito-idp:ListGroups"
],
"Resource": "arn:aws:cognito-idp:*:*:userpool/*"
},
{
"Sid": "CloudFrontManagement",
"Effect": "Allow",
"Action": [
"cloudfront:CreateDistribution",
"cloudfront:DeleteDistribution",
"cloudfront:GetDistribution",
"cloudfront:UpdateDistribution",
"cloudfront:ListDistributions",
"cloudfront:CreateInvalidation",
"cloudfront:CreateOriginAccessControl",
"cloudfront:ListOriginAccessControls",
"cloudfront:GetOriginAccessControl",
"cloudfront:DeleteOriginAccessControl",
"cloudfront:CreateFunction",
"cloudfront:PublishFunction",
"cloudfront:DescribeFunction"
],
"Resource": "*"
},
{
"Sid": "Route53Management",
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:GetHostedZone",
"route53:ListResourceRecordSets",
"route53:ChangeResourceRecordSets",
"route53:GetChange"
],
"Resource": "*"
},
{
"Sid": "ACMManagement",
"Effect": "Allow",
"Action": [
"acm:RequestCertificate",
"acm:DeleteCertificate",
"acm:DescribeCertificate",
"acm:ListCertificates",
"acm:AddTagsToCertificate"
],
"Resource": "*"
},
{
"Sid": "IAMRoleManagement",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:GetRole",
"iam:TagRole",
"iam:PassRole",
"iam:UpdateAssumeRolePolicy",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:GetRolePolicy"
],
"Resource": [
"arn:aws:iam::*:role/*serverless-cms*",
"arn:aws:iam::*:role/*-exec-role",
"arn:aws:iam::*:policy/*serverless-cms*"
]
},
{
"Sid": "CloudWatchLogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:DeleteLogGroup",
"logs:DescribeLogGroups",
"logs:PutRetentionPolicy"
],
"Resource": "arn:aws:logs:eu-west-2:*:log-group:/aws/lambda/*serverless-cms*"
}
]
}
- Click Next
- Name the policy:
ServerlessCMSDeploymentPolicy - Click Create policy
- Return to user creation and attach this custom policy
Step 3: Create Access Keys
- After creating the user, go to the Security credentials tab
- Scroll to Access keys section
- Click Create access key
- Select Command Line Interface (CLI)
- Check the confirmation box
- Click Next
- Add description tag:
Serverless CMS deployment - Click Create access key
Step 4: Configure AWS CLI
Configure the AWS CLI with your new credentials using a named profile:
aws configure --profile cms-deploy
Enter the following when prompted:
AWS Access Key ID [None]: YOUR_ACCESS_KEY_ID
AWS Secret Access Key [None]: YOUR_SECRET_ACCESS_KEY
Default region name [None]: eu-west-2
Default output format [None]: json
cms-deploy matches the configuration in src/main/serverless/config.json. Using this name ensures the deployment commands work without additional configuration.
Step 5: Verify Configuration
Test that your credentials work correctly:
aws sts get-caller-identity --profile cms-deploy
You should see output similar to:
{
"UserId": "AIDAXXXXXXXXXXXXXXXXX",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/serverless-cms-deployer"
}
If you see an error, verify:
- Access keys were entered correctly
- Profile name is
cms-deploy - Region is set to
eu-west-2
Step 6: Set Up Route 53 Hosted Zone
Before deploying, ensure you have a Route 53 hosted zone for your root domain:
Create Hosted Zone
- Navigate to Route 53 → Hosted zones
- Click Create hosted zone
- Enter your domain name (e.g.,
example.com) - Select Public hosted zone
- Click Create hosted zone
Update Domain Nameservers
After creating the hosted zone, you'll see 4 nameservers (NS records). Update your domain registrar to use these nameservers:
- Copy the 4 nameserver addresses from the NS record
- Log in to your domain registrar (GoDaddy, Namecheap, etc.)
- Find the nameserver settings for your domain
- Replace the existing nameservers with the AWS nameservers
- Save changes
Verify DNS Configuration
After nameserver propagation, verify DNS is working:
dig NS example.com +short
You should see the AWS nameservers listed.
Security Best Practices
Enable MFA
Add multi-factor authentication to the IAM user for additional security:
- Go to IAM → Users →
serverless-cms-deployer - Click Security credentials tab
- Under Multi-factor authentication (MFA), click Assign MFA device
- Follow the setup wizard
Rotate Access Keys
Regularly rotate access keys (every 90 days recommended):
- Create a new access key
- Update AWS CLI configuration with new key
- Test deployment with new key
- Delete old access key
Use Secrets Manager (Optional)
For CI/CD pipelines, store credentials in AWS Secrets Manager instead of environment variables:
# Store credentials
aws secretsmanager create-secret \
--name serverless-cms/deploy-credentials \
--secret-string '{"accessKeyId":"YOUR_KEY","secretAccessKey":"YOUR_SECRET"}' \
--profile cms-deploy