Cross Account Access to DynamoDb tables C# - c#

I have been dealing with this issue for which I am not able to find solution online anywhere.
I have a code which connects to AWS DynmoDb and performs read/write operations on one or more tables. This worked fine as long as my code and the DynamoDb table are in the same AWS account. Also the code uses the IAM Role attached to the Web Server. The role as all the necessary permissions assigned to it.
private AmazonDynamoDBClient GetDbClient(int ConnectionTimeOut, int ReadWriteTimeOut, int MaxRetry)
{
AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig
{
Timeout = TimeSpan.FromMilliseconds(ConnectionTimeOut),
ReadWriteTimeout = TimeSpan.FromMilliseconds(ReadWriteTimeOut),
MaxErrorRetry = MaxRetry
};
return new AmazonDynamoDBClient(clientConfig);
}
Recently I need to move my code to different AWS account and things started going crazy.
Following steps I have already taken.
VPC Peering done between the VPC in the old AWS account and the new AWS account.
Cross account permissions on the DynamobDb tables are given to the role which is used by the Web server on the new AWS Account.
With this change, I do not see any more permission errors but the code tries to look for the table on the new AWS account.
It is clear in the code that AWS AccountId is not used anywhere while creating AWS DynamoDb client. So I assume that I should be able to tell the code where to look for DynamoDb table. But the C# SDK of DynamoDb does not have any provision where I can provide AWS AccountId while creating DynamoDb client.
So my issue here is related to C# code to connect to DynamoDb service and not the IAM roles and permissions on AWS (for this I am able to fine plenty of solution).
Found this question aws cross account dynamodb access with IAM role with similar issue but it does not suggest the fix to do in the code.

One way to proceed is to use Security Token Service. First you need to assume a role and get temporary credentials:
Credentials GetCredentials(String roleArn)
{
using (var stsClient = new AmazonSecurityTokenServiceClient())
{
try
{
var response = stsClient.AssumeRole(new AssumeRoleRequest(roleARN));
if (response.HttpStatusCode == System.Net.HttpStatusCode.OK) return response.Credentials;
}
catch (AmazonSecurityTokenServiceException ex)
{
return null;
}
}
}
You can then use the credentials to initiate your DynamoDB client.
See another example here.

The AWS SDK and CLI (whether it's running locally or on (say) an EC2 instance) looks in the following locations for credentials:
Command line options
Environment variables
CLI credentials file
CLI configuration file
Container credentials
Instance profile credentials
If you have a credentials file configured, then, assuming we're running under the default profile, this will indirectly define the account under which it is running via the access key provided.
You can also define AWS-specific environment variables, such as AWS_ACCESS_KEY_ID which take precedence over the credentials file.
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html

Related

Service account is not authorized to manage project

I recently joined a team, and am adding Android Management Api to the already existing project. I added the management API, created service accounts with permissions, and am writing the .NET project to test it out.
I made a service account with Android Management User and Owner permissions. However, when I try to use the .NET library to make an enterprise, I get
The service androidmanagement has thrown an exception. HttpStatusCode is Forbidden. Caller is not authorized to manage project.
If it helps:
The API key I'm using is allowed to call any API, and the application name is a temporary one that does NOT match the project name. As for the service account with private key, I am using a FileStream to read a .json file downloaded when the service account was created.
This is my code, based on the sample app https://developers.google.com/android/management/sample-app
The error gets thrown on the createRequst.Execute()
string CreateEnterprise()
{
SignupUrlsResource.CreateRequest signupUrlRequest = managementService.SignupUrls.Create();
signupUrlRequest.ProjectId = cloud_project_id;
signupUrlRequest.CallbackUrl = "https://www.yahoo.com";
var signupUrl = signupUrlRequest.Execute();
string enterpriseToken = signupUrl.Url;
Console.WriteLine("Signup: " + enterpriseToken);
EnterprisesResource.CreateRequest createRequest = managementService.Enterprises.Create(new Enterprise());
createRequest.ProjectId = "Test Project";
createRequest.SignupUrlName = signupUrl.Name;
createRequest.EnterpriseToken = enterpriseToken;
var enterprise = createRequest.Execute();
return enterprise.Name;
}
Turns out the createRequest.ProjectId must match the project name that has the Android Management API, aka the project I'm working with.

Retrieving secrets from AWS with C# without storing access credentials in code base

I want to store sensitive data in my .Net Core C# app in AWS secret manager. I have created my secret in the portal but when I try to access it with the following code:
var config = new AmazonSecretsManagerConfig
{
ProxyHost = "MyProxyHost",
ProxyPort = 8080,
ProxyCredentials = CredentialCache.DefaultCredentials,
Timeout = TimeSpan.FromMinutes(5),
MaxErrorRetry = 1,
RegionEndpoint = RegionEndpoint.MyRegion,
};
var client = new AmazonSecretsManagerClient(config);
I then get this message when trying to use the secret manager client:
Unable to get IAM security credentials from EC2 Instance Metadata
Service
This is unsurprising as I haven't given any information that indicates I should be able to access secrets manager. I can gain access with the following code:
var config = new AmazonSecretsManagerConfig
{
ProxyHost = "MyProxyHost",
ProxyPort = 8080,
ProxyCredentials = CredentialCache.DefaultCredentials,
Timeout = TimeSpan.FromMinutes(5),
MaxErrorRetry = 1,
RegionEndpoint = RegionEndpoint.MyRegion,
};
var client = new AmazonSecretsManagerClient("MyAWSAccessKeyId", "MyAWSSecretAccessKey", config);
This though means that I have to store my sensitive data in my application, which is what I wanted to avoid in the first place. In Azure, using KeyVault this could be avoided using the right NuGet package and managed identities. I am wondering if there is a similar solution for AWS for both applications hosted in AWS and local development?
You can use IAM roles
Create an IAM role which has necessary permissions and attach the role to your EC2 instance. AmazonSecretsManagerClient will assume this IAM role when code is executed from an EC2 instance.
For local development : You can configure aws credentials with IAM role so that this role will be assumed when your code is executed from local machine.

Bad Request Creating Azure Batch user subscription pool using c# with vnet

I was trying to create a multi node pool in Azure Batch (User Subscription) using C#. I have assigned the RBAC role of "Virtual Machine Contributor" to the Vnet for "Microsoft Azure Batch" along with it's already existing Contributor role. While I was able to create it successfully without Virtual Network Configuration, as soon as I add the property it fails with a Bad Request Exception. This is the snippet of code which i am using.
pool.NetworkConfiguration = new NetworkConfiguration
{
DynamicVNetAssignmentScope = 0,
PublicIPAddressConfiguration = new PublicIPAddressConfiguration(IPAddressProvisioningType.NoPublicIPAddresses),
SubnetId = "/subscriptions/<subscriptionId>/resourceGroups/<ResrouceGroupName>/providers/Microsoft.Network/virtualNetworks/<vnetName>/subnets/<subnetName>",
};

Firestore C#: Missing or insufficient permissions

I am currently exploring Firebase's Cloud Firestore in C# and has encountered with the error which I could not resolve after searching SO. It seems that the resources for Firestore in C# is quite limited:
"Status(StatusCode=PermissionDenied, Detail=\"Missing or insufficient permissions.\")"
My code so far:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "FirebaseCsharpTest.json");
string project = "MyProjectId";
FirestoreDb db = FirestoreDb.Create(project);
Console.WriteLine("Created Cloud Firestore client with project ID: {0}", project);
AddPerson(db).GetAwaiter().GetResult();
}
public static async Task AddPerson(FirestoreDb db)
{
CollectionReference collection = db.Collection("users");
DocumentReference document = await collection.AddAsync(new
{
Name = new
{ First = "Ada", Last = "Lovelace" },
Born = 1815
});
}
}
I have checked on my Firebase console that the Firestore security rules are set to public (as of now, for testing sake). I have also ensured that the authentication json file is the right file generated from Google Developer Console as suggested in this post.
Is there something I'm missing?
EDIT:
My permissions on google cloud console:
Do check the projectID that you have been adding.
ProjectID is supposed to be the one that is specified in your json file.
This is a Cloud IAM issue and not a security rule issues. The C# server client library creates a privileged server environment that doesn't take into account Cloud Firestore security rules.. It seems that either your key file's service account doesn't have the correct IAM role or your code is not finding your keyfile.
Try using the full path to your keyfile instead of the relative path.
You can also try setting up a new service account and key file as described here.
Also, make sure you are changing the project variable:
string project = "NewFirebaseCsharpTest";
FirestoreDb db = FirestoreDb.Create(project);
Change the string project to the Id of the project and not the name of the project. The Id will probably start with the name and have a numeric suffix.
If that fails, go to the Log Explorer and query the logs. You will see an error that explains why your permission was denied.
You're never going to get enough information from the client-side for security reasons. Google isn't going to tell someone trying to gain access to something they shouldn't have access to what is going wrong. But, an admin can view the logs on the other side which will log all the information.

Accessing Google Cloud Datastore locally from ASP.NET throws Grpc.Core.RpcException: "Missing or insufficient permissions."

I'm following the Using Cloud Datastore with .NET tutorial. At some point it says that you can run the provided project locally by just pressing F5. When I do that I get the following exception
Grpc.Core.RpcException: 'Status(StatusCode=PermissionDenied, Detail="Missing or insufficient permissions.")'
This exception is thrown exactly at the _db.RunQuery(query) line.
var query = new Query("Book") { Limit = pageSize };
if (!string.IsNullOrWhiteSpace(nextPageToken))
query.StartCursor = ByteString.FromBase64(nextPageToken);
var results = _db.RunQuery(query);`
If I deploy the application to cloud it works as expected, no error. I've given datastore owner permissions to all accounts in Cloud IAM (Identity and Access Management) but it still doesn't work. Does anybody have any ideas?
As Jon Skeet pointed out, I was using the wrong json key locally. Previously I created a compute engine that has a separate service account. After I downloaded a new json key from Console -> IAM & Admin -> Service Accounts it worked locally as well.

Categories