aws / aws-sdk-net

The official AWS SDK for .NET. For more information on the AWS SDK for .NET, see our web site:
http://aws.amazon.com/sdkfornet/
Apache License 2.0
2.05k stars 853 forks source link

SSO_OIDC Register Client #2456

Open rlove opened 1 year ago

rlove commented 1 year ago

Describe the bug

I was trying to mimic the AWS CLI command of aws sso-oidc register-client --client-name testing --client-type public with the .NET SDK.

           var client = new AmazonSSOOIDCClient();
            RegisterClientRequest request = new RegisterClientRequest
            {
                ClientName = "testing",
                ClientType = "public"
            };
            var response = await client.RegisterClientAsync(request);

Last line throws Amazon.Runtime.AmazonServiceException : Unable to get IAM security credentials from EC2 Instance Metadata Service.

Expected Behavior

A response like I can get with RestSharp

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="RestSharp" Version="108.0.2" />
  </ItemGroup>

</Project>
using RestSharp;

var client = new RestClient("https://oidc.us-west-2.amazonaws.com/");
var request = new RestRequest("client/register",Method.Post);
request.AddHeader("Content-Type", "application/json");
var body = @"{""clientName"": ""testing"", ""clientType"": ""public""}";
request.AddParameter("application/json", body,  ParameterType.RequestBody);
var response = client.Execute(request);
Console.WriteLine(response?.Content);

Current Behavior

Message:  Amazon.Runtime.AmazonServiceException : Unable to get IAM security credentials from EC2 Instance Metadata Service.

Stack Trace:  DefaultInstanceProfileAWSCredentials.FetchCredentials() DefaultInstanceProfileAWSCredentials.GetCredentials() DefaultInstanceProfileAWSCredentials.GetCredentialsAsync() CredentialsRetriever.InvokeAsync[T](IExecutionContext executionContext) RetryHandler.InvokeAsync[T](IExecutionContext executionContext) RetryHandler.InvokeAsync[T](IExecutionContext executionContext) CallbackHandler.InvokeAsync[T](IExecutionContext executionContext) CallbackHandler.InvokeAsync[T](IExecutionContext executionContext) ErrorCallbackHandler.InvokeAsync[T](IExecutionContext executionContext) MetricsHandler.InvokeAsync[T](IExecutionContext executionContext)

Reproduction Steps

           var client = new AmazonSSOOIDCClient();
            RegisterClientRequest request = new RegisterClientRequest
            {
                ClientName = "testing",
                ClientType = "public"
            };
            var response = await client.RegisterClientAsync(request);

Last line throws Amazon.Runtime.AmazonServiceException : Unable to get IAM security credentials from EC2 Instance Metadata Service.

Possible Solution

No response

Additional Information/Context

Looking at AWS CLI Code, I was able to find in awscli/botocore/tokens.py

    def _client(self):
        config = Config(
            region_name=self._sso_config["sso_region"],
            signature_version=UNSIGNED,
        )
        return self._session.create_client("sso-oidc", config=config)

The looking UNSIGNED I find __init__.py find

# Used to specify anonymous (unsigned) request signature
class UNSIGNED(object):
    def __copy__(self):
        return self

    def __deepcopy__(self, memodict):
        return self

UNSIGNED = UNSIGNED()

AWS .NET SDK and/or Package version used

AWSSDK.SSOOIDC (3.7.1.27)

Targeted .NET Platform

.NET 6

Operating System and version

Windows 10

ashishdhingra commented 1 year ago

Hi @rlove,

Good afternoon.

Could you please share how the credentials are configured in your case in the default profile chain? You are using the parameterless var client = new AmazonSSOOIDCClient() client, in this case the SDK would try to find the AWS credentials in the default profile chain in the order specified at Credential and profile resolution.

I'm unsure how RestSharp in your case is able to simply submit POST request to https://oidc.us-west-2.amazonaws.com/ without specifying any credentials. However, SDK will probe for credentials and error out if it's unable to find the same.

Thanks, Ashish

rlove commented 1 year ago

I had no credentials configured right now. The reason that RestSharp works is the same reason the AWS CLI without credentials setup. There is not signing required for the API call, that is why I shared the code from AWS CLI. I also was able to call the API using Postman, with no special headers.

ashishdhingra commented 1 year ago

var client = new AmazonSSOOIDCClient(); RegisterClientRequest request = new RegisterClientRequest { ClientName = "testing", ClientType = "public" }; var response = await client.RegisterClientAsync(request);

@rlove As a workaround, the below code with AnonymousAWSCredentials appears to work:

using Amazon.SSOOIDC;
using Amazon.SSOOIDC.Model;
using Amazon.Runtime;

var client = new AmazonSSOOIDCClient(new AnonymousAWSCredentials());
RegisterClientRequest request = new RegisterClientRequest
{
    ClientName = "testing",
    ClientType = "public"
};
var response = await client.RegisterClientAsync(request);

Could you please try at your end?

Thanks, Ashish

ashishdhingra commented 1 year ago

In the service model that the SDK is generated from, this operation is marked with the authtype: none trait: https://github.com/aws/aws-sdk-net/blob/c0c4496e9df3da4ce9afdecaa603dd6f96aa7c04/generator/ServiceModels/sso-oidc/sso-oidc-2019-06-10.api.json#L53 We'll need to double-check if and how our code generator is utilizing that trait.

rlove commented 1 year ago

The workaround does work.