Repository: getmoto/moto
Pull request: KMS: get_public_key now works with alias (name and arn)
Fixes #8364 

The error provided was coming from the function `_validate_cmk_id()` which obviously raises an error when used with an alias, and if I understood correctly especially since `describe_key()` is using ` any_id_to_key_id()`.

Tests are passing and none seem to be broken.

Problem statement:
KMS get_public_key fails with alias
Hi, 

The following test, trying to use `get_public_key` with an alias is failing:

```python
import boto3
from moto import mock_aws

@mock_aws
def test():
    kms = boto3.client("kms", region_name="eu-west-1")
    key = kms.create_key(
        KeyUsage="SIGN_VERIFY",
        KeySpec="ECC_NIST_P256",
    )
    key_id = key["KeyMetadata"]["KeyId"]
    kms.create_alias(
        AliasName="alias/foo",
        TargetKeyId=key_id,
    )
    kms.get_public_key(KeyId="alias/foo")
```
raises the following exception:
```
/Users/xxx/Library/Caches/pypoetry/virtualenvs/motoreport-c38uzrXm-py3.11/bin/python /Users/xxx/PycharmProjects/cebidhem/motoReport/report/main.py 
Traceback (most recent call last):
  File "/Users/xxx/PycharmProjects/cebidhem/motoReport/report/main.py", line 18, in main
    kms.get_public_key(KeyId="alias/foo")
  File "/Users/xxx/Library/Caches/pypoetry/virtualenvs/motoreport-c38uzrXm-py3.11/lib/python3.11/site-packages/botocore/client.py", line 569, in _api_call
    return self._make_api_call(operation_name, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/xxx/Library/Caches/pypoetry/virtualenvs/motoreport-c38uzrXm-py3.11/lib/python3.11/site-packages/botocore/client.py", line 1023, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.errorfactory.NotFoundException: An error occurred (NotFoundException) when calling the GetPublicKey operation: Invalid keyId alias/foo
```

Somehow, the alias isn't recognized as an alias or it doesn't get translated as the actual keyId.

The only place where I can find the error `Invalid keyId ` is in the `_validate_cmk_id(self, key_id: str)`, which seems weird considering I try to use an alias.

I'm using: 
- Python 3.11.1
- moto 5.0.22
- boto3 1.35.75

I can also confirm that it works normally outside of moto with real AWS calls.

Hints from issue discussion:

Commit message: fix(kms): get_public_key now works with alias (name and arn)

Signed-off-by: Mehdi Bechiri <cebidhem@pm.me>

Patch to review:
diff --git a/moto/kms/responses.py b/moto/kms/responses.py
index b68ec20b08c7..7f5b9b674004 100644
--- a/moto/kms/responses.py
+++ b/moto/kms/responses.py
@@ -707,7 +707,6 @@ def get_public_key(self) -> str:
         key_id = self._get_param("KeyId")
 
         self._validate_key_id(key_id)
-        self._validate_cmk_id(key_id)
         key, public_key = self.kms_backend.get_public_key(key_id)
         return json.dumps(
             {
diff --git a/tests/test_kms/test_kms_boto3.py b/tests/test_kms/test_kms_boto3.py
index d1ccaf40292e..ce926266961b 100644
--- a/tests/test_kms/test_kms_boto3.py
+++ b/tests/test_kms/test_kms_boto3.py
@@ -1692,6 +1692,36 @@ def test_get_public_key():
     assert "EncryptionAlgorithms" not in public_key_response
 
 
+@mock_aws
+def test_get_public_key_with_alias():
+    client = boto3.client("kms", region_name="eu-west-1")
+    key = client.create_key(KeyUsage="SIGN_VERIFY", KeySpec="RSA_2048")
+    key_id = key["KeyMetadata"]["KeyId"]
+    client.create_alias(
+        AliasName="alias/foo",
+        TargetKeyId=key_id,
+    )
+    alias_arn = client.list_aliases()["Aliases"][0]["AliasArn"]
+
+    public_key_response_with_name = client.get_public_key(KeyId="alias/foo")
+    public_key_response_with_arn = client.get_public_key(KeyId=alias_arn)
+
+    assert "PublicKey" in public_key_response_with_name, (
+        "PublicKey" in public_key_response_with_arn
+    )
+    assert (
+        public_key_response_with_name["SigningAlgorithms"]
+        == key["KeyMetadata"]["SigningAlgorithms"]
+    ), (
+        public_key_response_with_name["SigningAlgorithms"]
+        == key["KeyMetadata"]["SigningAlgorithms"]
+    )
+
+    assert "EncryptionAlgorithms" not in public_key_response_with_name, (
+        "EncryptionAlgorithms" not in public_key_response_with_arn
+    )
+
+
 def create_simple_key(client, id_or_arn="KeyId", description=None, policy=None):
     with mock.patch.object(rsa, "generate_private_key", return_value=""):
         params = {}


Code review comments:
diff_hunk: @@ -1692,6 +1692,36 @@ def test_get_public_key():
     assert "EncryptionAlgorithms" not in public_key_response
 
 
+@mock_aws
+def test_get_public_key_with_alias():
+    client = boto3.client("kms", region_name="eu-west-1")
+    key = client.create_key(KeyUsage="SIGN_VERIFY", KeySpec="RSA_2048")
+    key_id = key["KeyMetadata"]["KeyId"]
+    client.create_alias(
+        AliasName="alias/foo",
+        TargetKeyId=key_id,
+    )
+    alias_arn = client.list_aliases()["Aliases"][0]["AliasArn"]
+
+    public_key_response_with_name = client.get_public_key(KeyId="alias/foo")
+    public_key_response_with_arn = client.get_public_key(KeyId=alias_arn)
+
+    assert "PublicKey" in public_key_response_with_name, (
+        "PublicKey" in public_key_response_with_arn
+    )
path: tests/test_kms/test_kms_boto3.py
text: @user1:
The second argument to `assert` is a message to inform the user what went wrong - you can't use it to chain assertions unfortunately.

As an example, this passes:
```
assert True, False
```
Because the `False` statement would only be used as a message if the condition (first argument) would be False.

But this example fails, and gives us the second argument as a description as to why it fails:
```
>>> assert False, True
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: True
```

TLDR: These assertions should probably just be split up:
```suggestion
    assert "PublicKey" in public_key_response_with_name
    assert "PublicKey" in public_key_response_with_arn
```

@author:
Thanks @user1 for the explanation, I'm not a true python dev _yet_ so it's helpful 👍 

The requested change has been pushed !