AWS Elasticsearch Access Policy ridiculously fickle - amazon-web-services

I want to create an AWS Elasticsearch with this policy, to enable specific access from IAM roles, set admin IPs, and public read only. ES Console keeps returning an error "Error setting policy". I can't work out why this would not be allowed?
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<id>:role/<lambda role 1 name>"
},
"Action": "es:ESHttpPost",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<id>:role/<lambda role 2 name>"
},
"Action": "es:ESHttpDelete",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"<ip1>",
"<ip2>",
"<ip3>"
]
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:ESHttpGet",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*"
}
]
}
It's in eu-west-1 and version 7.1. I've tried variations like es:* and putting principals in an array (like in the provided templates) but these are all rejected?! I can seemingly only have 2 statements, with 1 principal in each (* and 1 of these IAMs).
Is there a better recommended way? Like putting it behind API Gateway or something. I saw reverse proxy in the docs but this seems like a ridiculous overkill and $$$.

Related

I have a Query about AWS S3 bucket policy

I have a AWS S3 bucket in account A, This bucket was created by AWS Control Tower.
And used for collecting logs from all other account in my org,
I was trying to understand the bucket policy which is something like this
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSSLRequestsOnly",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::aws-controltower-logs-12345656-us-east-1",
"arn:aws:s3:::aws-controltower-logs-12345656-us-east-1/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
},
{
"Sid": "AWSBucketPermissionsCheck",
"Effect": "Allow",
"Principal": {
"Service": [
"config.amazonaws.com",
"cloudtrail.amazonaws.com"
]
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::aws-controltower-logs-12345656-us-east-1"
},
{
"Sid": "AWSConfigBucketExistenceCheck",
"Effect": "Allow",
"Principal": {
"Service": [
"config.amazonaws.com",
"cloudtrail.amazonaws.com"
]
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::aws-controltower-logs-12345656-us-east-1"
},
{
"Sid": "AWSBucketDelivery",
"Effect": "Allow",
"Principal": {
"Service": [
"config.amazonaws.com",
"cloudtrail.amazonaws.com"
]
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::aws-controltower-logs-12345656-us-east-1/o-1234/AWSLogs/*/*"
}
]
}
Now all other account in my org are able to dump there cloudtrail logs within this S3.
But i dont get one thing, i did not specified any particular or individual account number, but still other accounts are able to write content in this bucket,
Although i do see the principal which mentions relevant service name that can dump, but should,nt it only for this account itself ?
Let's analyze the rules one by one:
The first rule only says that no access without SSL is possible, it does nothing if SSL layer is present:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSSLRequestsOnly",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::aws-controltower-logs-12345656-us-east-1",
"arn:aws:s3:::aws-controltower-logs-12345656-us-east-1/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
},
The next two actions allow only read:
{
"Sid": "AWSBucketPermissionsCheck",
"Effect": "Allow",
"Principal": {
"Service": [
"config.amazonaws.com",
"cloudtrail.amazonaws.com"
]
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::aws-controltower-logs-12345656-us-east-1"
},
{
"Sid": "AWSConfigBucketExistenceCheck",
"Effect": "Allow",
"Principal": {
"Service": [
"config.amazonaws.com",
"cloudtrail.amazonaws.com"
]
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::aws-controltower-logs-12345656-us-east-1"
},
So the only action which allows any writing is this one:
{
"Sid": "AWSBucketDelivery",
"Effect": "Allow",
"Principal": {
"Service": [
"config.amazonaws.com",
"cloudtrail.amazonaws.com"
]
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::aws-controltower-logs-12345656-us-east-1/o-1234/AWSLogs/*/*"
}
]
}
And it says the following: You can put object under /o-1234/AWSLogs as long as you are one of the following two AWS services: Config or Cloudtrail.
Clearly, if knowing the bucket name and the org ID allows me to persuade Config or Cloudtrail to use that bucket I cannot see anything what would stop me from doing that except from some internal protection inside those services.
Based on this document:
https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-set-bucket-policy-for-multiple-accounts.html
It seems that for allowing an account 111111111111 to write to that bucket you should use the following ARN pattern: "arn:aws:s3:::myBucketName/optionalLogFilePrefix/AWSLogs/111111111111/*",
So while the answer provided by #izayoi does not provide any explanation, it is still correct. Cloudtrail service should guarantee you that it will always use that account id in the log, so you can narrow down the access by listing all your account numbers. Of course, it must be updated with every each new account.
Conclusion: Yes, knowing the bucket name and your organization ID should allow every AWS account in the world to use your bucket for Cloudtrail logging with the current policy...interesting. I would probably go with listing your account numbers.
"Resource": "arn:aws:s3:::aws-controltower-logs-12345656-us-east-1/o-1234/AWSLogs/*/*"
The 1st "*" enables all account numbers.

S3 Policy for Application Load Balancer

I am struggling with the setting up an S3 policy to give access to Application Load Balancer to push logs.
{
"Id": "Policy1629585161607",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1629585158642",
"Action": "s3:*",
"Effect": "Allow",
"Resource": "arn:aws:s3:::S3bucketname/*",
"Principal": {
"AWS":"arn:aws:iam:LoadBalancerId:root"
}
}
]
}
The LoadBalancerIdcame from the last part of the loan balancer's ARN; follows the trailing slash after the load balancer's name in the ARN.
The error got from S3 is Invalid principal in policy, what have I done wrong?
The AWS docs explain well what the policy should be exactly. Sadly, your policy is incorrect. It should follow the following format:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::elb-account-id:root"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::bucket-name/prefix/AWSLogs/your-aws-account-id/*"
},
{
"Effect": "Allow",
"Principal": {
"Service": "delivery.logs.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::bucket-name/prefix/AWSLogs/your-aws-account-id/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
},
{
"Effect": "Allow",
"Principal": {
"Service": "delivery.logs.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::bucket-name"
}
]
}
On top of that, bucket must be in same region and be encrypted.

How to allow only an IP/range access to AWS API Gateway resources

How best can I restrict access to certain routes in AWS API gateway by IP?
I want to allow only my ECS cluster to access certain routes in API gateway. I tried putting the ECS NAT gateway, the VPC CIDR range in aws:SourceIp but always get denied. I even tried my personal computer public IP address ... same results ... Is this the correct way? Or should I try IAM authorizers? The downside with IAM authorizer is I need to sign my API calls? Perhaps using the API Gateway SDK? Which means code change I prefer to avoid.
{
"Id": "MY_API_POLICY",
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": ["XX.XX.XX.XX/32"]
}
},
"Resource": [
"arn:aws:execute-*:*:apiid/stagename/*/private/route"
]
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-*:*:apiid/stagename/*/public/route"
]
}
]
}
As #Visal already mentioned is restricting the ip/range is the correct way. Here is the example: https://aws.amazon.com/de/blogs/compute/control-access-to-your-apis-using-amazon-api-gateway-resource-policies/
There is an example for a policy that allows the access for a certain ip range:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<account_idA>:user/<user>",
"arn:aws:iam::<account_idA>:root"
]
},
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:<account_idB>:qxz8y9c8a4/*/*/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:<account_idB>:qxz8y9c8a4/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": " 203.0.113.0/24"
}
}
}
]
}
Or if you want to deny the access then you will find this policy:
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:<account_idB>:qxz8y9c8a4/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}

How to simply make it private for general public? Without changing anything for my script

I'm kind of a newbie to AWS. I have the following data:
bucket ARN: arn:aws:s3:::my-bucket555
user: my-user-555
Access Key ID: "some key"
Secret access key: "some secret key"
And I have this policy of a bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket555"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-bucket555/*"
}
]
}
And also I have a bash script on a VPS which does some staff with my AWS account via API using the standard cli utility "aws s3" of Amazon. and the API keys
Problem: my bucket is publicly available at "https://s3.eu-west-2.amazonaws.com/my-bucket555". The url is obfuscated.
Question: how to make it private/non-public and still allow my bash script continue doing the job it's doing?
You have a few ways to accomplish that.
First, set as private your bucket.
Alternatives
Create an IAM Group and set it that policy, create a user within that group and use the access keys in your bash script.
Add to the policy a Condition to only accept accesses from a specific IP.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket555",
"Condition": {
"ForAnyValue:IpAddress": {
"aws:SourceIp": [
"210.75.12.75/16",
"210.75.24.75/16"
]
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-bucket555/*",
"Condition": {
"ForAnyValue:IpAddress": {
"aws:SourceIp": [
"210.75.12.75/16",
"210.75.24.75/16"
]
}
}
}
]
}

Add multiple domain access policy to AWS Elasticsearch Service (Static IP and Lambda ARN)

After setting up AWS Elasticsearch, I installed Logstash and Kibana proxy on a static IP server, and added this domain access policy on ES and it's working fine:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:ap-southeast-1:323137313233:domain/sg-es-logs/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"192.192.192.192"
]
}
}
}
]
}
Now I need to allow Lambda function to execute es:ESHttpDelete action on AWS ES, so I created the function with the existing role service-role/Elasticsearch then copied the relevent ARN from IAM Managment console to add it to AWS ES access policy, to come up with this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam:: 323137313233:role/service-role/Elasticsearch"
]
},
"Action": [
"es:*"
],
"Resource": "arn:aws:es:ap-southeast-1:323137313233:domain/sg-es-logs/*"
}
]
}
The problem is on ES I should either choose domain access policy for Static IP or ARN but not both. When I tried to merge them manually not by using the console it didn't work. I checked AWS documentation but they didn't mention if is that possible or not.
You can add multiple policy statements inside the Statement array in the JSON format of policy. So, your final policy would be something like:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:ap-southeast-1:323137313233:domain/sg-es-logs/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"192.192.192.192"
]
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam:: 323137313233:role/service-role/Elasticsearch"
]
},
"Action": [
"es:*"
],
"Resource": "arn:aws:es:ap-southeast-1:323137313233:domain/sg-es-logs/*"
}
]
}