Programster's Blog

Tutorials focusing on Linux, programming, and open-source

AWS IAM Examples

Below are some example configurations that I find useful in restricting applications to doing only what they need to do.

SES

SES Send Email From Specific IP

The following configuration only allows sending emails, and only if the requests for sending those emails came from the specified IP addresses. This means that even if your credentials leaked out somehow, people wouldn't be able to use them to send emails. They would have to have access to your server.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendRawEmail"
            ],
            "Resource": "*",
            "Condition": {
                "ForAnyValue:IpAddress": {
                    "aws:SourceIp": [
                        "x.x.x.x/32",
                        "x.x.x.x/32"
                    ]
                }
            }
        }
    ]
}

The above worked in the AWS cli for sending an email thorugh SES, but would not work when plugging details in for SMTP. For being able to send an SMTP request I created SMTP credentials in the AWS console (not IAM), and added the condition to the generated user retrospectively.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ses:SendRawEmail",
            "Resource": "*",
            "Condition": {
                "ForAnyValue:IpAddress": {
                    "aws:SourceIp": [
                        "x.x.x.x/32",
                        "x.x.x.x/32"
                    ]
                }
            }
        }
    ]
}

EC2

EC2 Snapshotting

If you need a user that just has the ability to create AMI images (which requires snapshotting of the ebs volumes), then this is what you need (courtesy of a post on serverfault):

{     
  "Effect": "Allow",
  "Action": [
    "ec2:Describe*",
    "ec2:CreateSnapshot",
    "ec2:CreateImage"
  ],
  "Resource": [
    "*"
  ]
}

S3

S3 Access To Specific Bucket

The following configuration will give full access to everything in the my-example-bucket bucket in S3 (as long as you own it).

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::my-example-bucket",
                "arn:aws:s3:::my-example-bucket/*"
            ]
        }
    ]
}

Below is the version I used to use:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::my-example-bucket"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:PutObjectVersionAcl",
        "s3:PutObjectAcl"
      ],
      "Resource": ["arn:aws:s3:::my-example-bucket/*"]
    }
  ]
}

The above (outdated) configuration won't let you upload to it through the web console. This alternative version from here did:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::my-bucket-name",
                "arn:aws:s3:::my-bucket-name/*"
            ]
        }
    ]
}

Elastic Transcoder

Elastic Transcoder - Restricted To Single Pipeline

Use the JSON configuration below, just swapping out the identifier for the pipeline.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "elastictranscoder:ListPipelines",
                "elastictranscoder:ListJobsByStatus",
                "elastictranscoder:ListPresets"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "elastictranscoder:Read*",
                "elastictranscoder:*Job",
                "elastictranscoder:*Preset",
                "elastictranscoder:List*"
            ],
            "Resource": [
                "arn:aws:elastictranscoder:*:*:job/*",
                "arn:aws:elastictranscoder:*:*:pipeline/2457257325632-wysdbs",
                "arn:aws:elastictranscoder:*:*:preset/*"
            ]
        }
    ]
}

I made up the pipeline ID 2457257325632-wysdbs in the example configuration, but it should be close enough to a real name that you should recognize that you want the short identifier, not the really long ARN.

References

Last updated: 26th August 2020
First published: 18th August 2020