Which is the "calling entity" when invoking Terraform with a role from another account? - terraform-provider-aws

I am using cross-account authorisation to create AWS resources with Terraform. That is to say:
I have an account "A" where I have a user.
I also have an account "B" where I have a role that is authorised to deploy resources within account "B".
My user account in "A" is authorised to assume the role in account "B".
When I run Terraform (with the "aws" provider), I have the credentials for user "A" in the aws credentials file.
My Terraform configuration has the provider block like this:
provider "aws" {
assume_role {
role_arn = "<ARN of roleB>"
}
}
The documentation for the aws_caller_identity data source says that it exposes details about "the calling entity", but it is unclear to me which "entity" this should be in my case: is it userA or roleB?

While I have been unable to find any official documentation that specifies which entity this refers to, by experimentation I have determined that "the calling entity" in this case is the role session in account "B" (note that while this is related to the role, it is not actually the role itself).
The ARN exposed by this data source looks like
"arn:aws:sts::<account B ID>:assumed-role/<name of role B>/<session name>"
The session name can be specified explicitly in the assume_role block, but if it is omitted then it is a semi-random-looking 19-digit number (I'm not sure whether this number is generated by Terraform or AWS).

Related

User assigned managed identity does not work with DefaultAzureCredential

In my Az Function I have system assigned managed identity enabled and a user assigned managed identity assigned.
I would like to use the user assigned managed identity to access some resources, so I put the following code to initialize ARMClient.
DefaultAzureCredentialOptions option = new DefaultAzureCredentialOptions
{
ManagedIdentityClientId = "xxxxxxx"
};
var credential = new DefaultAzureCredential(option);
_armClientUAI = new ArmClient(credential, subscriptionId);
Also, would like to grant access to the function itself to some resources, so I do not set AZURE_CLIENT_ID in App Setting as this will route to user assigned identity instead.
After deployed my function to Azure, it failed to access those resources that user assigned managed identity has been grant. Looks like it uses system assigne managed identity even I set client id explicitly.
From the doc here, it mentioned the check order for DefaultAzureCredential as follows, but did not say how it determines when both system assigned and user assigned are enabled.
EnvironmentCredential
ManagedIdentityCredential
SharedTokenCacheCredential
IntelliJCredential
AzureCliCredential
AzurePowerShellCredential
Fails if none of the credentials above could be created.
Tried to set the client id explicitly, but not working.

AWS Amplify Build Issue - StackUpdateComplete

When running amplify push -y in the CLI, my project errors with this message:
["Index: 0 State: {\"deploy\":\"waitingForDeployment\"} Message: Resource is not in the state stackUpdateComplete"]
How do I resolve this error?
The "Resource is not in the state stackUpdateComplete" is the message that comes from the root CloudFormation stack associated with the Amplify App ID. The Amplify CLI is just surfacing the error message that comes from the update stack operation. This indicates that the Amplify's CloudFormation stack may have been still be in progress or stuck.
Solution 1 – “deployment-state.json”:
To fix this issue, go to the S3 bucket containing project settings and deleted the “deployment-state.json” file in root folder as this file holds the app deployment states. The bucket should end with, or contain the word “deployment”.
Solution 2 – “Requested resource not found”:
Check the status of the CloudFormation stack and see if you can notice that the stack failed because of a “Requested resource not found” error indicating that the DynamoDB table “tableID” was missing and confirm that you have deleted it (possibly accidentally). Manually create the above DynamoDB table and retry to push again.
Solution 3A - “#auth directive with 'apiKey':
If you recieve an error stating that “#auth directive with 'apiKey' provider found, but the project has no API Key authentication provider configured”. This error appears when you define a public authorisation in your GraphQL schema without specifying a provider. The public authorization specifies that everyone will be allowed to access the API, behind the scenes the API will be protected with an API Key. To be able to use the public API you must have API Key configured.
The #auth directive allows the override of the default provider for a given authorization mode. To fix the issue specify “IAM” as the provider which allows to use an "Unauthenticated Role" from Cognito Identity Pools for public access instead of an API Key.
Below is the sample code for public authorisation rule:
type Todo #model #auth(rules: [{ allow: public, provider: iam, operations: [create, read, update, delete] }]) {
id: ID!
name: String!
description: String
}
After making the above changes, you can run “amplify update api” and add a IAM auth provider, the CLI generated scoped down IAM policies for the "UnAuthenticated" role automatically.
Solution 3B - Parameters: [AuthCognitoUserPoolId] must have values:
Another issue could occur here, where the default authorization type is API Key when you run the command “amplify add api” without specifying the API type. To fix this issue, follow these steps:
Deleted the the API
Recreate a new one by specifying the “Amazon Cognito user pool” as the authorization mode
Add IAM as an additional authorization type
Re-enable #auth directive in the newly created API Schema
Run “amplify push”
Documentation:
Public Authorisation
Troubleshoot CloudFormation stack issues in my AWS Amplify project

Configure authentication and synchronization with two LDAP in Alfresco 5.1

We perform migration from enterprise version Alfresco 4.2 to the 5.1.
There are two Active Directory domains (primary and child) in company, for this reason we configure two LDAP(AD) subsystems in Alfresco 5.1.
Structure of properties:
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap2
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap1
Problem is that authentication and synchronistaion work only for one ldap-ad subsystem (ldap1 or ldap2), which have first place in the list of authentication chain (ldap1 and ldap2 don't work together).
Authentication chain screenshot
For a example, if ldap1 have first place in the list, that user's login from ldap2 fails (and conversely!).
In this case I look error in alfresco.log:
Caused by: net.sf.acegisecurity.AuthenticationCredentialsNotFoundException: A valid SecureContext was not provided in the RequestContext
My properties:
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap1/ldap-ad-authentication.properties
ldap.authentication.active=true
ldap.authentication.allowGuestLogin=false
ldap.authentication.userNameFormat=%s#fake.local
ldap.authentication.java.naming.provider.url=ldap://fake.local:***
ldap.authentication.defaultAdministratorUserNames=fake_user
ldap.authentication.java.naming.referral=follow
ldap.synchronization.java.naming.security.principal=fake_user#fake.local
ldap.synchronization.java.naming.security.credentials=somepassword
ldap.synchronization.groupSearchBase=ou=Archiv,ou=FileServerGroups,ou=Groups,dc=fake,dc=local
ldap.synchronization.userSearchBase=dc=fake,dc=local
ldap.synchronization.groupDisplayNameAttributeName=description
ldap.synchronization.userOrganizationalIdAttributeNameCustom=distinguishedName
ldap.synchronization.com.sun.jndi.ldap.connect.pool=true
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap2/ldap-ad-authentication.properties
ldap.authentication.active=true
ldap.authentication.allowGuestLogin=false
ldap.authentication.userNameFormat=%s#gss.fake.local
ldap.authentication.java.naming.provider.url=ldap://gss.fake.local:***
ldap.authentication.defaultAdministratorUserNames=fake_user
ldap.authentication.java.naming.referral=follow
ldap.synchronization.java.naming.security.principal=fake_user#fake.local
ldap.synchronization.java.naming.security.credentials=somepassword%
ldap.synchronization.groupSearchBase=ou=Archiv,ou=FileServerGroups,ou=Groups,dc=gss,dc=fake,dc=local
ldap.synchronization.userSearchBase=dc=gss,dc=fake,dc=local
ldap.synchronization.groupDisplayNameAttributeName=description
ldap.synchronization.userOrganizationalIdAttributeNameCustom=distinguishedName
ldap.synchronization.com.sun.jndi.ldap.connect.pool=true
alfresco-global.properties
### Authentication ###
#authentication.chain=ldap1:ldap-ad,ldap2:ldap-ad,alfrescoNtlm1:alfrescoNtlm
authentication.chain=alfinst:alfrescoNtlm,ldap1:ldap-ad,ldap2:ldap-ad
Thanks in advance!
Finally, I resolved issue related to authentication users.
I put empty string of parametr:
ldap.authentication.userNameFormat=
for each LDAP subsystems in files ldap-ad-authentication.properties.
After, users from two ldaps could login successfully.
ldap.authentication.userNameFormat
Specifies how to map the user identifier entered by the user to that
passed through to LDAP. If set to an empty string (the default for the
ldap subsystem), an LDAP query involving
ldap.synchronization.personQuery and
ldap.synchronization.userIdAttributeName will be performed to resolve
the DN from the user ID dynamically. This allows directories to be
structured and does not require the user ID to appear in the DN.
If set to a non-empty value, the substring %s in this value will be
replaced with the entered user ID to produce the ID passed to LDAP.
This restricts LDAP user names to a fixed format. The recommended
format of this value depends on your LDAP server.

PACT - Using provider state

I am trying to use pact for validating the spring boot microservices. I have generated the pact file from consumer and verified it in the provider side using pact broker.
I have another use case where I need to execute some code before validating the pact file against actual service response. I read about state change URL and state change with closure to achieve it but couldnt get an example of how to achieve this. Can someone help?
My specific situation is: I have created a contract to update customer with id 1234 (First Name: test Last Name: user).
If this customer doesnt exist, then i would need to insert this data into DB by reading the first name, last name, id from the update request in pact file and additional info (city, state, phone number) through state change code.
So my question is, can i read the request data from pact file through state change instead of configuring the first name,last name and id in the verification side?
The state change URL is a hook you create on the provider to allow Pact to tell the provider what state it should be in at the start of the test. Before each test runs, the mock consumer taps the state change URL on your provider, and tells it the name of the state the test expects.
You need to do two things:
Configure a state change URL
Implement the state change endpoint on the provider
Configuring the state change URL
You can configure the state change URL in the provider verification settings. For example, using the the maven plugin:
<serviceProvider>
<name>provider1</name>
<stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl>
...
Or using the Gradle provider plugin:
hasPactWith('consumer1') {
stateChangeUrl = url('http://localhost:8080/tasks/pactStateChange')
...
Both of these tell the mock consumer to use localhost:8080/tasks/pactStateChange to change the state of the provider before each test.
Implementing the state change endpoint
The documentation linked above tells us that by default, the format of the request is a POST request of your state string and any parameters:
{ "state" : "a provider state description", "params": { "a": "1", "b": "2" } }
To use this, you implement something like the following untested code on the provider :
#RequestMapping(value = "tasks/pactStateChange", method = RequestMethod.POST)
ResponseEntity<?> stateChange(#RequestBody ProviderState state) {
if (state.state == "no database") {
// Set up state for the "no database" case here
} else if state.state == "Some other state" {
// Set up state here
} else if ... // Other states go here
...
}
return ResponseEntity.ok().build()
}
Please excuse any spring boot errors in that example - I'm not a spring boot person, but you can see the general principle.
With the state change URL, pact doesn't tell the provider any setup details. It just tells the provider the pre-agreed state string that you used in your test. This could be something like "foo exists". Then, when implementing the handler for the state change URL, you detect "foo exists", and do any explicit setup there.
if (state.state == "foo exists") {
// do whatever you need to set up so that foo exists
repository.clear()
repository.insert(new Foo("arguments that foo needs",12))
}
If you'd like to know more about the intent of provider states, have a read of the wiki page on provider states.
How to do this in your specific case
You asked:
Can i read the request data from pact file through state change instead of configuring the first name,last name and id in the verification side?
You might be confused about the intention of the contract tests - each test is a combination of state and request.
So instead of using one test to say:
My test is to request a customer update. If the customer exists, then I expect X response, and if it doesn't, then I expect Y response
you use two tests to say:
When I submit an update to the customer record (in the state when the customer exists), then I expect X response.
When I submit an update to the customer record (in the state where the customer does NOT exist), then I expect Y response.
These tests are two separate items in your Pact contract.
The intention is not to include details of the setup in the contract. On the consumer side, your state is just a string that says something like "Customer with id=1234 exists".
On the Provider side, your state change endpoint detects that URL and creates the state as appropriate. This is usually done in a hard-coded way:
if (state == "Customer with id=1234 exists") {
Database.Clear()
Database.Insert(new Customer(1234, "John","Smith"))
} else if (state == "No customers exist") {
Database.Clear()
}
You don't want to do this in a parameterised way by parsing the state string, because then you're creating a new complex contract between the test consumer and the provider.
The consumer tests shouldn't know anything about how to set provider state, they should just know what state is required by the test (by name only). Similarly, the provider doesn't need to know what's being tested, it just needs to know how to turn state names into actual state.

Check other user's role membership (IsInRole, WindowsIdentity/Principal)

I'm writing ASP.NET code to run on an internal network where Windows Authentication will be used. Certain operations will require me to run a group membership check on other users (not the current user)
NOTE: I am NOT trying to impersonate this account, or access any information in the context of this other user. Just trying to find out what kind of user they are for internal business logic.
My first thought was to use
new WindowsPrincipal(new WindowsIdentity("MACHINENAME\\username"))
.IsInRole("MACHINENAME\\Group1")
However, the WindowsIdentity constructor fails with a SecurityException "The name provided is not a properly formed account name".
If I strip MACHINENAME\ from the parameter, I get a different error: There are currently no logon servers available to service the logon request
The WindowsTokenRoleProvider role provider explicitly only works with the current user, and will not check other user accounts.
Are there security restrictions to checking roles of other users? Would it make a difference if the web server was on a domain and I were checking domain accounts?
In the end, I'll need to have this work on an AD domain, but would prefer a solution that will work on either local or AD accounts.
Thank you
UPDATE: I've been able to test this on a domain now -- the code does work in an AD context so long as I don't use the domain name (test "username" against "Group1", not "DOMAIN\username" against "DOMAIN\Group1")
So how would I get this to work in the context of local users and groups?
Based on Rob A's comment, PrincipalContext and UserPrincipal are the classes I apparently need to use:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine))
{
var u = UserPrincipal.FindByIdentity(ctx, IdentityType.Name, "username");
var b = u.IsMemberOf(ctx, IdentityType.Name, "Group1");
var groups = u.GetAuthorizationGroups();
}
And by altering the ContextType, can switch between local accounts and AD accounts. I wish this was built into a RoleProvider, but I guess that's something I'd have to do for myself.

Resources