Proper access policy for Amazon Elastic Search Cluster - amazon-web-services

I've recently started using the new Amazon Elasticsearch Service and I can't seem to figure out the access policy I need so that I can only access the services from my EC2 instances that have a specific IAM role assigned to them.
Here's an example of the access policy I currently have assigned for the ES domain:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::[ACCOUNT_ID]:role/my_es_role",
]
},
"Action": "es:*",
"Resource": "arn:aws:es:us-east-1:[ACCOUNT_ID]:domain/[ES_DOMAIN]/*"
}
]
}
But as I said, this doesn't work. I log into the EC2 instance (which has the my_es_role role attached to it) and attempt to run a simple curl call on the "https://*.es.amazonaws.com" end point, I get the following error:
{"Message":"User: anonymous is not authorized to perform: es:ESHttpGet on resource: arn:aws:es:us-east-1:[ACCOUNT_ID]:domain/[ES_DOMAIN]/“}
Does anyone know what I have to change in the access policy in order for this to work?

You can lock access down to IAM-only, but how will you view Kibana in your browser? You could setup a proxy (see Gist and/or NPM module) or enable both IAM and IP-based access for viewing results.
I was able to get both IAM access IP-restricted access with the following Access Policy. Note the order is important: I could not get it working with the IP-based statement before the IAM statement.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxxxxxxxxxxx:root"
},
"Action": "es:*",
"Resource": "arn:aws:es:us-west-2:xxxxxxxxxxxx:domain/my-elasticsearch-domain/*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:us-west-2:xxxxxxxxxxxx:domain/my-elasticsearch-domain/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"192.168.1.0",
"192.168.1.1"
]
}
}
}
]
}
My EC2 instance has an instance profile with the
arn:aws:iam::aws:policy/AmazonESFullAccess
policy. Logstash should sign requests using the logstash-output-amazon-es output plugin. Logstash running on my EC2 instance includes an output section like this:
output {
amazon_es {
hosts => ["ELASTICSEARCH_HOST"]
region => "AWS_REGION"
}
# If you need to do some testing & debugging, uncomment this line:
# stdout { codec => rubydebug }
}
I can access Kibana from the two IPs in the access policy (192.168.1.0 and 192.168.1.1).

According to AWS doc and as you (and I) just tested, you cannot restrict access to an AWS ES domain to a role/account/user/... and simply cURL it!
Standard clients, such as curl, cannot perform the request signing that is required of identity-based access policies. You must use an IP address-based access policy that allows anonymous access to successfully perform the instructions for this step.
(http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-gsg-search.html)
So you have basically two solutions:
change your access policy and restrict it to IP(s), I think you cannot use private IP because your ES cluster does not seems to belong to your VPC (default or not). Please use the public IP
sign your request: http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-signing-service-requests
Signing your request is probably the best solution if you want to keep your access policy as is (which is more flexible than restricting to an IP), but it seems to be a bit more complex. I haven't tried so far and I cannot find any doc to help.

A bit late to the party, but I was able to deal with the exact same issue by adding signature to my requests.
If you use Python (like I do), you can use the following library to make it particularly easy to implement:
https://github.com/DavidMuller/aws-requests-auth
It worked perfectly for me.

You may either use resource based policy or identity based policy rather than IP based policy which is like hard coding the IP address.
But you need to use Signature version 4 to sign the request
For Java implementation please refer http://mytechbites.blogspot.in/2017/04/secure-amazon-elastic-search-service.html

You just need to full user name in elastic search policy.
In this case, you can get your full user name from the error message itself.
In my case:
"arn:aws:sts::[ACCOUNT_ID]:assumed-role/[LAMBDA_POLICY_NAME]/[LAMBDA_NAME]"
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:sts::xxxxxxxxxxxx:assumed-role/[lambda-role]/[full-lambda-name]"
]
},
"Action": "es:*",
"Resource": "arn:aws:es:[region]:xxxxxxxxxxxxx:domain/[elasticsearch-domain-name]/*"
}
]
}

Role ARN needs to be changed. it will be looks like "arn:aws:iam::[ACCOUNT_ID]:role/service-role/my_es_role"

I'm also trying to do this, and I got it working using the Allow access to the domain from specific IP(s) option with the Elastic IP of my EC2 instance (could also work using the instance's private IP, but I'm not too sure)

Related

AWS IAM autorisation: how to give access to service with aws console?

I have a "root" account.
I created an "admin" account which has all the right.
I created an account "dev" and I want it to only have acces to certain services:
s3
dynamoDB
cloudWatch
API Gateway
Lambda
Cognito
So I created a policy with the aws console editor and I gave full access to theses ressources and allows everything, it gave me this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:*",
"apigateway:*",
"lambda:*",
"dynamodb:*",
"cognito-idp:*"
],
"Resource": "*"
}
]
}
Looks good to me (not specific enough but good for a beginner).
Problem: I created db, lambda, api gateway, etc... but I can't see the services with this, which autorisation should I give for the "dev" role to see the items in the AWS console ?
I found it, I only needed to switch my region in the top right corner of the console. (shame on me)

AWS SCPs and how to block access to certain resources

I want to block access to certain resources that I create as a base set up in new AWS account in my Organization. I want to do this for all users except Admins. The access only for admin part is solved with this design:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"ArnNotEquals": {
"aws:PrincipalArn": [
"arn:aws:iam::*:role/myadminrole",
"arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/sso-region/AWSReservedSSO_myrolename"
]
}
}
}
]
}
As you can see in the above role everything is denied for everyone except the admins, this not i want to do I want to block access to certain resources. The simplest way to do so is just to list the resources I want to block access to under "Resource". But this will resolve in manual work to keep this SCP up to date and this is something I try to avoid. So my second idea was to use tags and base the deny of access on them with a condition like this:
"Condition": {"ForAllValues:StringEquals": {"aws:TagKeys": ["mytagkey"]}}
But when I ran into this issue where some AWS services don't support authorisation based on tags, see link:
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html#:~:text=Yes-,AWS%20Lambda,Partial%C2%B2,-Amazon%20Lightsail
Does anyone know a good way to solve my issue? Or does I just have yo accept that I have to manually update my SCP?
After investigation both from me and AWS support this is not possible at the moment. So the answer is that you need to manually update your SCPs.

AWS Elastic Search With Kibana - Authentication through IP-based policies or resource-based policies DO NOT WORK AT ALL

at my serverless.yaml file I create and restrict the access to my ElasticSearch domain service and Kibana. However, through AWS Resource-based policies or AWS IP-based policies I am not able to access kibana.
The restriction was done following the AWS Tutorial Source below
For example:
enter link description here
However, it does not worked and I got the error when I tried to access Kibana: {"Message":"User: anonymous is not authorized to perform: es:ESHttpGet"}
So, it means that Kibana requires recently an user. So, the only way now is to use AWS Cognito??
Thank you very much in advance!
Cheers,
Marcelo
You need to modify your access policy as
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:ap-south-1:****:domain/es-cert/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"88.8.888.8"
]
}
}
}
]
}
In the "aws:SourceIp" section, you need to add your public IP address
I would question which ElasticSearch domain you created. Did you create it with VPC or HTTP access? I did just this the other day and in trying to implement my IP access policy, nothing worked. I finally found this article, recreated my domain, applied my access policy, similar to what you have above, and it worked.
“If you enabled VPC access, you can't use IP-based policies. Instead, you can use security groups to control which IP addresses can access the domain.”
https://docs.aws.amazon.com/opensearch-service/latest/developerguide/createupdatedomains.html

IAM Policy to give readonly access to a specific DBCluster

I am trying to create an IAM Managed Policy to assign to QA users that will give them readonly access to a specific DBCluster, the QA cluster.
So far I haven't been able to limit the access to the specific cluster, I can only get it to work if the Resource tag is set to all
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"rds:Describe*",
"rds:ListTagsForResource"
],
"Resource": "*",
"Effect": "Allow",
"Sid": "DescribeQADatabase"
}
]
}
I've tried changing the Resource tag to my specific DBCluster ARN, but when I do that nothing shows in the RDS page in the AWS Console
Side question, if I look at the AWS Provided AmazonRDSReadOnlyAccess I see that it gives access to a bunch of other AWS Resources like ec2 instances. Is there a document/resource I can use that will basically tell me all the dependencies I will need if I want to give access to a specific resource?

How do I limit access to S3 Bucket for particular IAM Role?

We want to store some data on S3 and only allow EC2 instances or a particular user with a particular IAM role to access them. Unfortunately we're having some trouble doing this.
We set a policy on the bucket like this
{
"Version": "2012-10-17",
"Id": "SamplePolicy",
"Statement": [
{
"Sid": "Stmt1331136294179",
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::our-account-number:user/the-user",
"arn:aws:iam::our-account-number:role/the-role"
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::the-bucket/*"
},
{
"Sid": "Stmt1331136364169",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::our-account-number:user/the-user",
"arn:aws:iam::our-account-number:role/the-role"
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::the-bucket/*"
}
]}
When we access the Bucket (using boto) with users key it works fine, from a local machine or any EC2 instance.
But, when we access the bucket from Boto we get
ClientError: An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
I've confirmed that the instance has the correct IAM role
curl http://169.254.169.254/latest/meta-data/iam/info/
{
"Code" : "Success",
"LastUpdated" : "2015-10-22T09:09:31Z",
"InstanceProfileArn" : "our-account-number:instance-profile/the-role",
"InstanceProfileId" : "instance-rpofile-id"
}
I've also tried to remove the policy from the bucket, which indeed makes it accessible again.
Any ideas how to handle this?
The sample I shared here is a simplified version I've been doing for debugging. In production, we want are forcing the object to be encrypted with KMS and have an access policy on the key as well. We like that solution alot, and prefer to keep it if we can.
Thanks
One mistake with this that I've made many times involves your ARN
For some permissions you need it on the bucket itself (no /*)... and some you need on it's contents.
I'd attempt to use what you currently have, only include both, so something like...
"Resource": ["arn:aws:s3:::the-bucket/*", "arn:aws:s3:::the-bucket"]
The issue here is that for NotPrincipal you have to provide the specific session role. Unfortunately, when using InstanceProfiles (or Lambda), this session role is dynamic. AWS does not support wildcards in the principal field so therefore it is basically impossible to use NotPrincipal with an InstanceProfile.
See AWS support response here that acknowledges it as a known limitation: https://forums.aws.amazon.com/message.jspa?messageID=740656#740656