# 401 after updating API Key role descriptors

**URL:** <https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756>\
**Category:** Elasticsearch\
**Tags:** elastic-stack-security, language-clients\
**Created:** [March 15, 2023, 1:25pm UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756 "2023-03-15T13:25:38Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mateusz\_Migala](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mateusz_migala/32/110541_2.png) [@Mateusz\_Migala](https://discuss.elastic.co/u/Mateusz_Migala)\
**Post date:** [March 15, 2023, 1:25pm UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/1 "2023-03-15T13:25:38Z")

</div>

Hello,

I'm trying to limit default privileges of the API key when it's being created. By default it's created by terraform with superuser account which I feel has too much access.

We want to use the API\_Key to connect to Elasticsearch from the .NET application. Application will run querying, indexing operations, it will create, delete indexes, should also be able to monitor cluster health connectivity.

Now by default if I just create the API key with permissions of the super user this is what we get.  
With these permissions the applications works just fine

```auto
{
  "api_keys": [
    {
      "id": "",
      "name": "",
      "creation": ,
      "invalidated": ,
      "username": "",
      "realm": "found",
      "metadata": {},
      "role_descriptors": {},
      "limited_by": [
        {
          "superuser": {
            "cluster": [
              "all"
            ],
            "indices": [
              {
                "names": [
                  "*"
                ],
                "privileges": [
                  "all"
                ],
                "allow_restricted_indices": false
              },
              {
                "names": [
                  "*"
                ],
                "privileges": [
                  "monitor",
                  "read",
                  "view_index_metadata",
                  "read_cross_cluster"
                ],
                "allow_restricted_indices": true
              }
            ],
            "applications": [
              {
                "application": "*",
                "privileges": [
                  "*"
                ],
                "resources": [
                  "*"
                ]
              }
            ],
            "run_as": [
              "*"
            ],
            "metadata": {
              "_reserved": true
            },
            "transient_metadata": {
              "enabled": true
            }
          }
        }
      ]
    }
  ]
}

```

Now when I changed the role\_descriptors to limit access of the key it looks like this

```auto
{
  "api_keys": [
    {
      "id": "",
      "name": "",
      "creation": ,
      "invalidated": ,
      "username": "",
      "realm": "found",
      "metadata": {},
      "role_descriptors": {
        "role-a": {
          "cluster": [
            "monitor"
          ],
          "indices": [
            {
              "names": [
                "*"
              ],
              "privileges": [
                "all"
              ],
              "allow_restricted_indices": false
            }
          ],
          "applications": [],
          "run_as": [],
          "metadata": {},
          "transient_metadata": {
            "enabled": true
          }
        }
      }
    }
  ]
}

```

But now we get 401 error

> System.InvalidOperationException : Could not authenticate with the specified node. Try verifying your credentials or check your Shield configuration. Call: Status code 401

Now since I left all of the indices permissions with all privileges I'm not sure which part if the one that is causing the issues. I feel like the key doesn't need most of the Cluster privileges since it causes security vulnerability.

---

<div class="post-metadata">

**Author:** ![stephenb](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/stephenb/32/40856_2.png) [@stephenb](https://discuss.elastic.co/u/stephenb)\
**Post date:** [March 15, 2023, 2:23pm UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/2 "2023-03-15T14:23:41Z")

</div>

Hi @Mateusz_Migala

What version of the stack are you using?

And what call / API are you sending when you get the error, how and where are you using it?

It's always very helpful if you actually show the command you're running and then the output, otherwise we're just guessing.

When I look at the role you only included one role of monitoring which is very limited. So what are you trying to accomplish??

---

<div class="post-metadata">

**Author:** ![Mateusz\_Migala](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mateusz_migala/32/110541_2.png) [@Mateusz\_Migala](https://discuss.elastic.co/u/Mateusz_Migala)\
**Post date:** [March 15, 2023, 2:32pm UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/3 "2023-03-15T14:32:31Z")

</div>

We are using 8.6.1 version of elastic.

So I kind of went over the use case I thought. It seems all operations started failing. Search, Indexing, index creation. They are run from .NET app using API key to connect to the cluster.

but one example would be index creation.

```auto
        public async Task<CreateIndexResponse> IndexCreateAsync(IndexName index, Func<CreateIndexDescriptor, ICreateIndexRequest> selector = null, CancellationToken ct = default)
        {
            return await _elasticClient.Indices.CreateAsync(index, selector, ct);
        }

```

and this is how the connection part looks like

```auto
        private static ElasticClient CreateElasticClient(IConfiguration configuration)
        {
            string apiKey = configuration[ConfigurationConstants.ElasticApiKey];
            string elasticPrivateLinkUrl = configuration[ConfigurationConstants.ElasticPrivateLinkUrl];

            ConnectionSettings settings =
                new ConnectionSettings(new Uri(elasticPrivateLinkUrl))
                    .ApiKeyAuthentication(new ApiKeyAuthenticationCredentials(apiKey))
                    .DefaultIndex(IndexingConstants.DefaultMdcId)
                    .EnableDebugMode()
                    .MaximumRetries(ElasticsearchIndexSettings.MaxRetries)
                    .MaxRetryTimeout(ElasticsearchIndexSettings.MaxRetryTimeout)
                    .EnableApiVersioningHeader();

            return new ElasticClient(settings);

```

So I'm not sure which privilege I removed is causing the issue.

Yes I included only Monitoring. What would be the cluster role that is needed to do the operations I mentioned ?

---

<div class="post-metadata">

**Author:** ![stephenb](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/stephenb/32/40856_2.png) [@stephenb](https://discuss.elastic.co/u/stephenb)\
**Post date:** [March 15, 2023, 2:47pm UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/4 "2023-03-15T14:47:15Z")

</div>

So I would test using CURL or postman first to eliminate the variables.

Are you using SHEILD plugin or something I do not recognize that error... Shield is ancient... maybe that is an old error message... but I searched the code and I do not see that error message.

Are you only using core Elastic Components?

---

<div class="post-metadata">

**Author:** ![Mateusz\_Migala](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mateusz_migala/32/110541_2.png) [@Mateusz\_Migala](https://discuss.elastic.co/u/Mateusz_Migala)\
**Post date:** [March 16, 2023, 6:37am UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/5 "2023-03-16T06:37:05Z")

</div>

Well we are using PrivateLink for connections. I don't know anything about Shield . I can try some testing using Postman. Trying to get to the bottom of it. I thought someone might know something I'm missing right of the bat.

---

<div class="post-metadata">

**Author:** ![stephenb](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/stephenb/32/40856_2.png) [@stephenb](https://discuss.elastic.co/u/stephenb)\
**Post date:** [March 16, 2023, 6:42am UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/6 "2023-03-16T06:42:12Z")

</div>

The weird part is you should get a very descriptive error saying that whatever you're trying to do requires role A, B and C.

That's the normal error message when you try to do something you don't have authorization for.

I haven't seen that error before.

I would definitely try to curl or postman furst to see what's going on.. just POST a simple document to s new index.

---

<div class="post-metadata">

**Author:** ![Mateusz\_Migala](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mateusz_migala/32/110541_2.png) [@Mateusz\_Migala](https://discuss.elastic.co/u/Mateusz_Migala)\
**Post date:** [March 16, 2023, 7:19am UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/7 "2023-03-16T07:19:18Z")

</div>

Maybe the error is specific to NEST ? it's the .NET elastic client we are using.

Also I just did few quick tests and if I manually create the API key with the permissions I mentioned everything works fine.

```auto
POST /_security/api_key
{
  "name": "test",
  "role_descriptors": { 
    "role-a": {
      "cluster": ["monitor"],
      "index": [
        {
          "names": ["*"],
          "privileges": ["all"]
        }
      ]
    }
  }
}

```

The issue started occurring when I tried to set the same set of permissions using terraform.

```auto
# Create Elastic API KEY
resource "elasticstack_elasticsearch_security_api_key" "api_key" {
  name = "elastic_api_key"

    role_descriptors = jsonencode({
    role-a = {
      cluster = ["monitor"],
      indices = [
        {
          names = ["*"],
          privileges = ["all"]
        }
      ]
    }
  })

  elasticsearch_connection {
    endpoints = [coalesce(var.ELASTICPRIVATELINKURL, "${ec_deployment.elasticsearch.elasticsearch[0].https_endpoint}")]
    username = ec_deployment.elasticsearch.elasticsearch_username
    password = ec_deployment.elasticsearch.elasticsearch_password
  }
  
    lifecycle {
      ignore_changes = [
        elasticsearch_connection[0].endpoints[0]
      ]
  }  
}

```

but I just verified using dev console and if I run

`GET /_security/api_key?id=nameOfKey`

both keys are identical. The only difference being username and realm since I created the key using my account and not elastic superuser account. Also one key was just created using Post and the second one was Post and then Put (but i dont see how that makes any difference)

---

<div class="post-metadata">

**Author:** ![Mateusz\_Migala](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mateusz_migala/32/110541_2.png) [@Mateusz\_Migala](https://discuss.elastic.co/u/Mateusz_Migala)\
**Post date:** [March 16, 2023, 7:37am UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/8 "2023-03-16T07:37:33Z")

</div>

Ok I did one more quick check

This error is always shown if the API key is incorrect

```auto
        private static ElasticClient CreateElasticClient(IConfiguration configuration)
        {
            string apiKey = configuration[ConfigurationConstants.ElasticApiKey];
            string elasticPrivateLinkUrl = configuration[ConfigurationConstants.ElasticPrivateLinkUrl];

            ConnectionSettings settings =
                new ConnectionSettings(new Uri(elasticPrivateLinkUrl))
                    .ApiKeyAuthentication(new ApiKeyAuthenticationCredentials("KeyThatDoesntExist"))
                    .DefaultIndex(IndexingConstants.DefaultMdcId)
                    .EnableDebugMode()
                    .MaximumRetries(ElasticsearchIndexSettings.MaxRetries)
                    .MaxRetryTimeout(ElasticsearchIndexSettings.MaxRetryTimeout)
                    .EnableApiVersioningHeader();

            return new ElasticClient(settings);
        }

```

will cause

```auto
System.InvalidOperationException : Could not authenticate with the specified node. Try verifying your credentials or check your Shield configuration. Call: Status code 401 from: POST /temp-index-for-integration-tests-add3cafd-fb59-4de2-93ad-e716b24749ce/_search?pretty=true&error_trace=true&typed_keys=true. ServerError: Type: security_exception Reason: "unable to authenticate with provided credentials and anonymous access is not allowed for this request"

```

Still not sure though why I started to see this error for the key with updated roles. Maybe I will try to rerun the terraform script again since the roles seem to be ok.

---

<div class="post-metadata">

**Author:** ![Mateusz\_Migala](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/mateusz_migala/32/110541_2.png) [@Mateusz\_Migala](https://discuss.elastic.co/u/Mateusz_Migala)\
**Post date:** [March 16, 2023, 8:16am UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/9 "2023-03-16T08:16:40Z")

</div>

Ok I found what the issue was...

We keep Elastic API key reference in Azure Key vault and Azure App config.

Azure app config wasnt correctly updated. Will need to look into the reason why.

Anyway the error I mentioned is basically saying API key doesnt exist.

I've seen 403s when there was something wrong with actual permissions

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [April 13, 2023, 8:16am UTC](https://discuss.elastic.co/t/401-after-updating-api-key-role-descriptors/327756/10 "2023-04-13T08:16:51Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
