Single use secret in Hashicorp vault - hashicorp-vault

Is it possible with any secret engine to have a "single use" password?
I have a command that generates an rsa keypair for users, and would like them to retrieve their private key. I can obviously print it out, or write to file etc, but thought it would be nice if it was stored in a "single use" place in vault? Then the user could retrieve it via the UI, and know that no-one else has viewed it. If someone else viewed it they would need to regenerate.
Basically can we have a vault key that can only be read once?

You can create a policy that only has access to that secret, for example
# policy: rsa
path "secret/rsa" {
capabilities = ["read"]
}
and then create a wrapped token for that policy, for example
$ vault token create -policy=rsa -num_uses=1 -wrap-ttl=120
Key Value
--- -----
wrapping_token: s.9QFJ8mRxGJD0e7kFfFIbdpDM
wrapping_accessor: S0zKNUr2ENbnCtj0YyriO31b
wrapping_token_ttl: 2m
wrapping_token_creation_time: 2019-12-17 09:45:42.537057 -0800 PST
wrapping_token_creation_path: auth/token/create
wrapped_accessor: VmBKXoc19ZLZlHGl0nQCvV6r
This will generate a wrapped token.
You can give that to your end user and they can unwrap it with
VAULT_TOKEN="s.3Kf3Xfn58Asr3bSDkRXATHrw" vault unwrap
which will generate a token.
With that token, the user will be able to login to vault and retrieve the rsa creds only once since the token will be invalid afterwards.
You can now guarantee that the creds have only been used from the target user as the wrapped token can be unwrapped only once.
Note: you might need to adjust num_uses when you create the token if your end user goes through the UI as the UI might use the token to perform more than one actions.
more info

Related

Change AWS temporary credential expiry time

I have following code in my iOS application which is integrated with Amazon Cognito identity pool. My identity pool is integrated with criipto which is a third party authentication provider. token parameter is the authentication token that I get from third party provider.
func federateToIdentityPools(token : String) async throws -> Bool{
guard let authCognitoPlugin = try Amplify.Auth.getPlugin(
for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else {
fatalError("Unable to get the Auth plugin")
}
do {
let result = try await authCognitoPlugin.federateToIdentityPool(
withProviderToken: token, for: .oidc("test.criipto.id"))
print("Federation successful with result: \(result.credentials.accessKeyId)")
print("Federation successful with result: \(result.credentials.secretAccessKey)")
print("Federation successful with result: \( result.credentials.expiration)")
return true
} catch {
print("Failed to federate to identity pools with error: \(error)")
return false
}
}
I get printed the credentials successfully. Now I want to change the expiration time for the credentials. For that what I did is changing the Maximum session duration from IAM roles for Authenticated role in identity pool.
But that doesn't change the credential expiration time.
Question 1 - How to change the expiration time for the temporary AWS credential that I get?
Question 2 - Is there a way that we can refresh the temporary AWS credentials when expired without federated identity provider's token?
You can go directly to the Cognito Authenticated Role within IAM and change the max session time.
Here's how to do this through the Console: https://docs.aws.amazon.com/IAM/latest/UserGuide/roles-managingrole-editing-console.html#roles-modify_max-session-duration
You can also update the role using the CLI (update-role) and updating the max-session-duration parameter.
You can also use the UpdateRole API and you can set this using the MaxSessionDuration parameter.
On your second question, I don't believe this will be possible as is. Maybe there could be some way to cache things, but I would avoid going down this path. The token issued from the IdP must still be valid and therefore you might want to explore how long tokens are valid from the IdP. I'm not familiar with the IdP you're using, but I would look into what's possible there.

Signing JWT token with per-user key rather than application-wide

Normally, JWT tokens are signed with an application-wide secret or an asymmetric key pair. However, I am integrating into a system that uses a per-user secret that is in fact the salt of the password in the Users table (called private_key there).
I find this system a bit odd. It was apparently meant to make sure that if a user changed his password, the issued tokens would stop working. But it does kill the main advantage of JWT: for any other system to be able to accept the token without having to call the Auth service to validate it. In this case, decoding the token requires to decode it without validation, fetching the database user/private key and then validating it.
The .net code:
List<Claim> claims = new List<Claim>()
{
new Claim("UserUUID", user.UserUUID.ToString())
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(user.PrivateKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _configuration["JwtIssuer"],
audience: _configuration["JwtIssuer"],
claims: claims,
expires: expirationDate,
signingCredentials: creds);
return Ok(new
{
access_token = new JwtSecurityTokenHandler().WriteToken(token),
expires_on = expirationDate
});
Is this actually reasonable and if there is an issue other than validation issues, why is it bad ?
I have seen a similar question but it doesn't address whether this scheme is a good idea, bad idea or just useless burden.

Explanations on JWT Tokens structure

I'm trying to understand JWT tokens usage but I'm getting lost on the theorycal part.
I have some questions about JWT Tokens structure, in order to make this question a sort of documentation for new users, providing it with a logic order, I will write them in bold below as long as I list a sample JWT content.
I will also summary them in the end of the question
A "classic" JWT token is composed as follows:
[HEADER].[PAYLOAD].[SIGNATURE]
In detail:
HEADER
{
"alg": "HS256",
"typ": "JWT"
}
Which contains the following fields:
ALG = Encryption algorythm (using the default HS256 could be fine)
TYP = simply tells that it's a JWT
PAYLOAD
{
"sub": "1234567890",
"name": "MrJohnDoe",
"iat": 1516239022
}
SUB = Is an OPTIONAL parameter. It's the subject of the token. (credits: see #cassiomolin answer)
According to: Where to store user id in jwt, it looks like you can use it to store your user ID in it.
NAME = The username
IAT = Token creation date and time, expressed in unix timestamp. (Thanks to #jps and #JeanRostan in the comments below)
SIGNATURE
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
SECRET = Unique key known just by the server. To not confuse with the current user password, which should never be used for this! (thanks to #jps in the comments below)
What is sub? Can you please provide me an example of what it could be in a common usage?
The sub claim identifies the principal that is the subject of the JWT. In other other, it can hold the username of the user who you issued the token to.
From the RFC 7519:
4.1.2. "sub" (Subject) Claim
The sub (subject) claim identifies the principal that is the
subject of the JWT. The claims in a JWT are normally statements
about the subject. The subject value MUST either be scoped to be
locally unique in the context of the issuer or be globally unique.
The processing of this claim is generally application specific. The
sub value is a case-sensitive string containing a StringOrURI
value. Use of this claim is OPTIONAL.

Identity server3 : User Info endpoint returns null Claims

I am using Authorization Code flow and I am trying to get the user information using user info endpoint, but I am not getting claims. I've enabled IncludeInIdToken for some claims like name profile email and when decode Idtoken I was not able to see the above claims.
I've tried by debugging the method GetProfileDataAsync, here I found the "Name" property coming null, since I am using the AD group I need this Name property here.
I tried to save "Name" into global variable in LocalLoginAsync method and used the same in GetProfileDataAsync method. Now I have added claims to the TaskResult, but I am getting count '0' in the response
When I request for tokens by using code I am able to see the following result in Claims
and I am not able to see those claims in IdToken,
Next, time when request using user info endpoint by using access token I am not getting any Claim except "sub" or no Name property.
How can I get Claim with User Info endpoint response
I've tried by debugging the code and found the issue, since I am doing the mistake like
return Task.FormResult(identity.Claims.where(x=>context.RequestedClaimTypes.Contains(x.Types)));
instead of doing
context.IssuedClaims = identity.Claims.where(x=>context.RequestedClaimTypes.Contains(x.Types));
return Task.FromResult(0);
But still I am getting the username(Name) property null with user info endpoint..,
I am assuming that you are requesting the profile scope in your request. If this is true then username is not a valid scope and does not form part of the list of standard claims for this scope. you should rename your claim to either nickname or preferred_username

Is showing x-amz-credential or any amazon stuff publicly okay in form?

In my form it showing my policy and x-amz-credential, x-amz-alorithm, x-amz-signature, my bucket, etc...
data-form-data = "{"key":"/uploads/temporary/<some random numbers/letters>/${filename}",
"success_action_status":"201",
"acl":"public-read",
"Content-Type":"image/jpeg",
"policy":"<bunch of random numbers/letters",
"x-amz-credential":"<your-access-key-id>/<date>/<aws-region>/<aws-service>/aws4_request",
"x-amz-algorithm":"<some random numbers/lettering>",
"x-amz-date":"<some random numbers/letters>",
"x-amz-signature":"<some random numbers/letters>"}"
data-url="https://<bucket-name>.s3.amazonaws.com"
data-hose="<bucket-name>.s3.amazonaws.com
Yes, that's fine. It's designed not to expose sensitive data, and this data isn't sensitive.
Your AWS Access Key Secret is the only value that is secret and must not be revealed. (There's also a sensitive intermediate value called the signing key that's generated from the secret, which you won't see unless you wrote your own V4 request signing code). The signature is derived from the signing key and other request parameters; the signing key is service and region specific and is derived from the secret and used in your code, then discarded... and both of these values are generated using in a one-way process that makes it computationally infeasible to reverse-engineer.

Categories