aws glue IAM role cant connect to aws opensearch - amazon-web-services

I have a Glue job to push data into AWS OpenSearch. Everythings works perfectly when I have an "open" permission on OpenSearch, for example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:<region>:<accountId>:domain/<domain>/*"
}
]
}
This works without issue. The problem is I want to secure my OpenSearch domain to only the role running the glue job.
I attempted to do that starting basic with:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<accountId>:role/AWSGluePowerUser"
]
},
"Action": [
"*"
],
"Resource": [
"*"
]
}
]
}
This disables all access to OpenSearch which I want, however it also blocks it for Glue even though the jobs a running with the AWSGluePowerUser role set.
An error occurred while calling o805.pyWriteDynamicFrame. Cannot detect ES version - typically this happens if the network/Elasticsearch cluster is not accessible or when targeting a WAN/Cloud instance without the proper setting 'es.nodes.wan.only'
Which I assume is because the Glue job can no longer see the OpenSearch cluster. Keep in mind everything works when using the "default" access policy for OpenSearch.
I have my glue job configured to use the IAM role AWSGluePowerUser which also has AmazonOpenSearchServiceFullAccess policy attached.
I'm not sure where I've gone wrong here?
Edit: Here is where/how I've set the roles for the Glue job, I assume this is all I needed to do?
From Glue Job Details

I believe this is not possible because the AWS Glue Elasticsearch connector is based on an open-source Elasticsearch Spark library that doest not sign requests using AWS Signature Version 4 which is required for enforcing domain access policies.
If you take a look at the key concepts for fine-grained access control in OpenSearch, you'll see:
If you choose IAM for your master user, all requests to the cluster must be signed using AWS Signature Version 4.
If you visit the Elasticsearch Connector for AWS Glue AWS Marketplace page, you'll notice that the connector itself is based on an open-source implementation:
For more details about this open-source Elasticsearch spark connector, please refer to this open-source connector online reference
Under the hood, AWS Glue is using this library to index data from Spark dataframes to the Elasticsearch endpoint. Since this open-source library (maintained by the Elasticsearch community) does not have support for signing requests using using AWS Signature Version 4, it will only work with the "open permission" you've referenced. This is hinted at in the big picture on fine-grained access control:
In general, if you enable fine-grained access control, we recommend using a domain access policy that doesn't require signed requests.
Note that you can always fall back us using a master user based on username/password:
Create a master user (username/password) for the OpenSearch domain's fine-grained access control configuration.
Store the username/password in an AWS Secrets Manager secret as described here.
Attach the secret to the AWS Glue connector as described here.
Hope this helps!

I usually take a "deny everyone except" approach in these situations
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "es:*",
"Resource": [
"*"
],
"Condition": {
"ArnNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::<accountId>:role/AWSGluePowerUser"
]
}
}
}
]
}

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 permissions for Fargate and SSM

I'm trying to create some infrastructure for a service I am building on AWS using AWS Fargate. I'm using SSM as a value store for some of my application configuration, so I need both the regular permissions for Fargate as well as additional permissions for SSM. However, after banging my head against this particular wall for a while, I've come to the conclusion that I just don't understand AWS IAM in general or this problem in particular, so I'm here for help.
The basis of my IAM code comes from this tutorial; the IAM code is actually not in that tutorial but rather in this file in the github repo linked to that tutorial. I presume I need to retain that STS permission for something although I'm not entirely sure what.
I've converted the IAM code from the tutorial into a JSON document because I find JSON easier to work with than the Terraform native thing. Here's what I've come up with. It doesn't work. I would like to know why it doesn't work and how to fix it. Please ELI5 (explain like I'm 5 years old) because I know nothing about this.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:GetParameters",
"secretsmanager:GetSecretValue",
"kms:Decrypt",
"sts:AssumeRole"
],
"Principal": {
"Service": ["ecs-tasks.amazonaws.com"]
}
}
]
}
At a minimum, your ECS task should have below permissions:
Ability to assume a role
Resource level permissions
In the example, you have referred, An IAM Role is created with the following:
A trust relationship is attached. <-- To enable ECS task to assume an IAM role
AWS managed policy AmazonECSTaskExecutionRolePolicy is attached. <-- Resource permissions
So, in order to retrieve the SSM parameter values, add below resource permissions.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:Describe*",
"ssm:Get*",
"ssm:List*"
],
"Resource": [
"arn:aws:ssm:*:*:parameter/{your-path-hierarchy-to-parameter}/*"
]
}
]
}
If your Secrets uses KMS, then grant necessary kms permissions (kms:Decrypt). Refer specifying-sensitive-data for reference.

Its possible to use AWS Athena using a VPC endpoint?

I would like to know if it is possible to create a VPC endpoint for AWS Athena and restrict to only allow certain users (that MUST BE in my account) to use the VPC endpoint. I currently use this VPC endpoint policy for a S3 endpoint and I would need something similar to use with AWS Athena.
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<MY_ACCOUNT_ID>:user/user1",
"arn:aws:iam::<MY_ACCOUNT_ID>:user/user2",
...
]
},
"Action": "*",
"Resource": "*"
}
]
}
The problem I'm trying to solve is to block developers in my company, that are logged in a RDP session inside my company VPN, to offload data to a personal AWS account. So I would need a solution that blocks access to the public internet, so I think a VPC endpoint should be the only option, but I accept new ideas.
Yes you can, check out this doc.
https://docs.aws.amazon.com/athena/latest/ug/interface-vpc-endpoint.html
Also, keep in mind to adopt a encryption at rest and transit when query data via athena, the results always by default is open even if it's saved on a encrypted s3 bucket.

Proper access policy for Amazon Elastic Search Cluster

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)

Auth0 and S3 Buckets

I have a question.
I'm using Auth0 and AWS SDK to access to some buckets on S3. I have a question. Is there any way to restrict the access to S3 Buckets without he use of bucket policies? Maybe using metadata provided by Auth0.
Thanks for all
Maybe you're looking for something like this https://github.com/auth0/auth0-s3-sample to restrict access for users on their resources.
IAM Policy for user buckets (restricted to these users only)
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowEverythingOnSpecificUserPath",
"Effect": "Allow",
"Action": [
"*"
],
"Resource": [
"arn:aws:s3:::YOUR_BUCKET/dropboxclone/${saml:sub}",
"arn:aws:s3:::YOUR_BUCKET/dropboxclone/${saml:sub}/*"]
},
{
"Sid": "AllowListBucketIfSpecificPrefixIsIncludedInRequest",
"Action": ["s3:ListBucket"],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::YOUR_BUCKET"],
"Condition":{
"StringEquals": { "s3:prefix":["dropboxclone/${saml:sub}"] }
}
}
]
}
But, if the users have shareable group folders it may become more tricky, I'm looking into it myself a.t.m.
Checkout this pdf: https://www.pingidentity.com/content/dam/pic/downloads/resources/ebooks/en/amazon-web-services-ebook.pdf?id=b6322a80-f285-11e3-ac10-0800200c9a66 on page 11 LEVERAGE OPENID CONNECT FOR AWS APIS the use case is similar.
So, an option could be to do the following
[USER] -> [Auth0] -> [AWS (Federation/SAML)] -> [exchange temporary AWS credentials] -> [use temp. credentials to access S3]
Hope it helped and even if it is quite a long time ago you asked this question, other users maybe benefit. If you've found a better solution, please share it.
To restrict access to S3 buckets you must use Amazon IAM.
When using Auth0, you're basically exchanging your Auth0 token for an Amazon Token. Then, with that Amazon token you're calling S3. That means that in order to restrict access to certain parts of S3 you're going to have to change the permissions on Amazon's token, which means you'll need to play with IAM.
Makes sense?
Cheers!