How I Made Sense of the Master User in the Amazon OpenSearch Service (previously, ElasticSearch)

Yann Stoneman
4 min readSep 11, 2021
Photo by Jacqueline Godany on Unsplash

If you are reading this post, it’s probably because you are knees deep into figuring out how to enable fine-grained access control. And that means you are delegating most of your identity and access management to the controls of the Open Distro for ElasticSearch (now OpenSearch) instead of AWS IAM. This is explained in the below screenshot from the wizard for creating an ElasticSearch (ES) domain:

The AWS console experience for creating a master user

The master user in ES can be either a username and password or an AWS IAM principal (a role or a user). Both just function to get you in the door of ES as a master user. It’s like the username and password combo for the master user of an RDS MySQL database.

So the policies on the IAM role or user don’t even matter?

Right. So you might as well give zero permissions to the IAM role or IAM user, and, as long as the machine or person can authenticate to that role or user, then they will have the powers of “master user” in ES.

The AWS IAM role or IAM user serve purely for authentication—the policies on that role or user have no bearing on the authorization of the ES master user. Those are handled via the controls provided within ES itself.

I’ve never needed to create an AWS IAM user without permissions. Show me what you mean!

Right. This made me scratch my head too. But if you do a GitHub search for code of how an IAM-based master user is implemented, you’ll get templates where the actual user or role does not have any permissions.

For example, I grabbed this from the official aws/aws-cdk repo on GitHub:

An IAM user and a partial AWS ES domain definition

The IAM user in that template has no permissions. It’s just specified as the master user in the ES domain definition.

And as another example, taken from an unofficial repo of a Solution Architect at AWS, this time with an AWS IAM role as the master user:

An IAM role and a partial AWS ES domain definition

Again, the template has no permissions for the master user, this time defined as an IAM role.

So does the master user just have complete permissions that don’t need to be explicitly defined within AWS IAM?

Yes, the master user is the master of AWS ES, regardless of what the IAM role or user is.

How do I test that the permissionless IAM user can really access ES?

To check this out quickly on a test ES domain in a test AWS account, disregarding all security best-practices to isolate testing of the master user, I

  • launched an ES domain, set as public facing (non-VPC-based)
  • created an IAM user called User1 with no policies
  • designated master user as User1
  • and used the default open resource-based policy (aka, the domain access policy), in which nothing is limited:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:us-east-1:12345678901:domain/test/*"
}
]
}
An access policy allowing open access

Once the domain was provisioned, I plopped the endpoint in the browser to verify that it was publicly accessible, but in need of authentication:

“Authentication finally failed” shows me that it’s public but requires authentication

Then I grabbed a Python code snippet from the Amazon documentation on “Signing HTTP requests to Amazon ElasticSearch Service.” This helped me to see in action how the master user’s IAM user credentials are used to authenticate a request:

When we run that code locally with a random IAM user’s credentials like those of my machine’s default user called OtherUser, we get an error saying,

AuthorizationException(403, 'security_exception', 'no permissions for [indices:data/write/index] and User [name=arn:aws:iam::12345678901:user/OtherUser, backend_roles=[], requestedTenant=null]')

When I updated the code to have boto3 grab my named profile User1 instead, it worked.

With,

credentials = boto3.Session(profile_name='User1').get_credentials()

I got back the desired response:

{
"_index":"movies",
"_type":"_doc",
"_id":"5",
"_version":1,
"_seq_no":0,
"_primary_term":1,
"found":true,
"_source":{
"title":"Moneyball",
"director":"Bennett Miller",
"year":"2011"
}
}

And how do you integrate with an external identity provider like Okta?

Same way as with any AWS IAM role, you just add an assume role policy to the role:

{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Federated":"<COPY & PASTE SAML ARN VALUE HERE>"
},
"Action":"sts:AssumeRoleWithSAML",
"Condition":{
"StringEquals":{
"SAML:aud":"https://signin.aws.amazon.com/saml"
}
}
}
]
}

More details in the Okta Setup SSO article.

So that’s how I made sense of the master user in the AWS ElasticSearch Service.

Follow Yann Stoneman

Last but not least, if you are not a Medium Member yet and plan to become one, I kindly ask you to do so using the following link. I will receive a portion of your membership fee at no additional cost to you.

--

--

Yann Stoneman

Solutions Architect. 13x AWS certified. All opinions are my own. Support this blog and others by becoming a member here: https://ystoneman.medium.com/membership