Allow user to update/delete certain policies(Hashicorp Vault) - hashicorp-vault

Description
I am using Hashicorp's Vault ,version 1.7.0, free version.
I would like to allow a certain range of policies that a user can assign/delete to a group. In that way he can add or delete entities user to the group from the UI.
What I have done
Bellow is written into blocks the overall policy file.
{
capabilities = ["list"]
}
#To show the identity endpoint from the UI
path "/identity/*"{
capabilities = ["list" ]
}
#policies that I would like the user to have the ability to #assign to the group.
path "/sys/policies/acl/it_team_leader"{
capabilities = ["read", "update", "list"]
}
path "sys/policies/acl/it_user"{
capabilities = ["read", "update","list"]
}
path "sys/policies/acl/ui_settings"{
capabilities = ["read", "update", "list"]
}
path "sys/policies/acl/personal_storage"{
capabilities = ["read", "update","list"]
}
#Group id that the user have full access
path "/identity/group/id/2c97485a-754f-657a-5a8b-62b08a3ce8cb" {
capabilities = ["sudo","read","update","create","list"]
}
What is the issue
Lets assume that I have an super-privileged policy that provides access to the the whole secret engine.
From the UI I am able to assign to that group the super-priveleged policy and basically allow a restricted user to assign this super policy to the whole group.
When I extended the policy with :
path "sys/policies/acl/**super-priveleged**" {
capabilities = ["deny"]
}
is just restricting the policy to be read from the UI.
Appending the group path with allowed_parameters such us :
capabilities = ["sudo","read","update","create","list"]
denied_parameters = {
"policies" = ["it_user","it_team_leader",etc]
}
I receive a permission denied error(403).
Appending with denied parameters :
path "/identity/group/id/2c97485a-754f-657a-5a8b-62b08a3ce8cb" {
capabilities = ["sudo","read","update","create","list"]
denied_parameters = {
"policies" = ["super-policy"]
}
is not functioning and I am still allowed to assign the super policy.
I also tried wildcards with the same result.
Is it even possible to restrict one/a range of policies that can be assigned from the Vault UI?
Thanks in advance if you made it so far.

Found the solution, to restrict user to update certain policies the allowed parameters fields should encapsulate a list and add an asterisk key with an empty list.
Note : The order of the policies assigned from the UI should comply with the order that is written in the .hcl file.
path "/identity/group/id/2c97485a-754f-657a-5a8b-62b08a3ce8cb"
{
capabilities = ["sudo","read","update","create","list"]
allowed_parameters = {
"policies" = [["policy1","policy2","policy3"]]
"*" = []
}
}

Related

Terraform: update resources only when Vault secret data has changed

This should be fairly easy, or I might doing something wrong, but after a while digging into it I couldn't find a solution.
I have a Terraform configuration that contains a Kubernetes Secret resource which data comes from Vault. The resource configuration looks like this:
resource "kubernetes_secret" "external-api-token" {
metadata {
name = "external-api-token"
namespace = local.platform_namespace
annotations = {
"vault.security.banzaicloud.io/vault-addr" = var.vault_addr
"vault.security.banzaicloud.io/vault-path" = "kubernetes/${var.name}"
"vault.security.banzaicloud.io/vault-role" = "reader"
}
}
data = {
"EXTERNAL_API_TOKEN" = "vault:secret/gcp/${var.env}/micro-service#EXTERNAL_API_TOKEN"
}
}
Everything is working fine so far, but every time I do terraform plan or terraform apply, it marks that resource as "changed" and updates it, even when I didn't touch the resource or other resources related to it. E.g.:
... (other actions to be applied, unrelated to the offending resource) ...
# kubernetes_secret.external-api-token will be updated in-place
~ resource "kubernetes_secret" "external-api-token" {
~ data = (sensitive value)
id = "platform/external-api-token"
type = "Opaque"
metadata {
annotations = {
"vault.security.banzaicloud.io/vault-addr" = "https://vault.infra.megacorp.io:8200"
"vault.security.banzaicloud.io/vault-path" = "kubernetes/gke-pipe-stg-2"
"vault.security.banzaicloud.io/vault-role" = "reader"
}
generation = 0
labels = {}
name = "external-api-token"
namespace = "platform"
resource_version = "160541784"
self_link = "/api/v1/namespaces/platform/secrets/external-api-token"
uid = "40e93d16-e8ef-47f5-92ac-6d859dfee123"
}
}
Plan: 3 to add, 1 to change, 0 to destroy.
It is saying that the data for this resource has been changed. However the data in Vault remains the same, nothing has been modified there. This update happens every single time now.
I was thinking on to use the ignore_changes lifecycle feature, but I assume this will make any changes done in Vault secret to be ignored by Terraform, which I also don't want. I would like the resource to be updated only when the secret in Vault was changed.
Is there a way to do this? What am I missing or doing wrong?
You need to add in the Terraform Lifecycle ignore changes meta argument to your code. For data with API token values but also annotations for some reason Terraform seems to assume that, that data changes every time a plan or apply or even destroy has been run. I had a similar issue with Azure KeyVault.
Here is the code with the lifecycle ignore changes meta argument included:
resource "kubernetes_secret" "external-api-token" {
metadata {
name = "external-api-token"
namespace = local.platform_namespace
annotations = {
"vault.security.banzaicloud.io/vault-addr" = var.vault_addr
"vault.security.banzaicloud.io/vault-path" = "kubernetes/${var.name}"
"vault.security.banzaicloud.io/vault-role" = "reader"
}
}
data = {
"EXTERNAL_API_TOKEN" = "vault:secret/gcp/${var.env}/micro-service#EXTERNAL_API_TOKEN"
}
lifecycle {
ignore_changes = [
# Ignore changes to data, and annotations e.g. because a management agent
# updates these based on some ruleset managed elsewhere.
data,annotations,
]
}
}
link to meta arguments with lifecycle:
https://www.terraform.io/language/meta-arguments/lifecycle

How to set global tags in Pulumi Azure Native

In a stack specific settings file (i.e. Pulumi.dev.yaml), if location is set (i.e. azure-native:location) then resource group location is set automatically and location for resources is derived from resource group location. Now I am trying to apply common tag for all resources i.e. CreatedBy: Pulumi. Is there any way to set common/global tags, similar to azure-native:location in settings file (Pulumi.dev.yaml) ?
Expected: both location and tags will be set from Pulumi.dev.yaml
config:
azure-native:location: japaneast
azure-native:tags:
CreatedBy: Pulumi
var mainRgArgs = config.RequireObject<JsonElement>(KEY_RESOURCE_GROUP_ARGS);
var mainRgName = mainRgArgs.GetProperty(RESOURCE_GROUP_NAME).GetString()!;
var mainRg = new ResourceGroup(RESOURCE_GROUP_MAIN, new ResourceGroupArgs
{
ResourceGroupName = mainRgName
//Location =
//Tags =
});
It isn't possible to set the tags automatically, because tags aren't a required API property.
The reason location is a provider argument is because every resource requires a location when it's created. That isn't true for tags.
However, it is possible to automatically add tags to resources that are taggable (which isn't all resources) using a transformation
Transformations allow you to inject properties into every resource, regardless of whether you've set that value on your resource explicitly. You will however have to set a list of taggable resources, because not every Azure resource is taggable.
A function which will register tags on resources will look something like this:
export function registerAutoTags(autoTags: Record<string, string>): void {
pulumi.runtime.registerStackTransformation((args) => {
if (isTaggable(args.type)) {
args.props["tags"] = { ...args.props["tags"], ...autoTags };
return { props: args.props, opts: args.opts };
}
return undefined;
});
}
and then you can use those tags by calling the function:
registerAutoTags({
"user:Project": pulumi.getProject(),
"user:Stack": pulumi.getStack(),
"user:Cost Center": config.require("costCenter"),
});
There's more information on this (albeit for AWS, not Azure) here. You can find a list of Azure resources that are support tags here

how can I attach multiple pre-existing AWS managed roles to a policy?

I want to associate existing policies in AWS to a role, I am using the terraform tool
I want to associate these policies, this code is with the aws cloudformation tool:
AWSCodeCommitFullAccess
AWSCodeBuildAdminAccess
AWSCodeDeployFullAccess
AWSCodePipelineFullAccess
AWSElasticBeanstalkFullAccess
try with the attach
data "aws_iam_policy" "attach-policy" {
arn = ["arn:aws:iam::aws:policy/AWSCodeCommitFullAccess", "arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess", "arn:aws:iam::aws:policy/AWSCodeDeployFullAccess", "arn:aws:iam::aws:policy/AWSCodePipelineFullAccess"]
}
resource "aws_iam_role_policy_attachment" "tc-role-policy-attach" {
role = "${aws_iam_role.toolchain-role.name}"
policy_arn = "${data.aws_iam_policy.attach-policy.arn}"
}
You go with the right direction with terraform resource aws_iam_role_policy_attachment but need some adjustment.
AWS managed policies' ARN are exist in the system. For example, if you need attach the first managed policy to an IAM role,
resource "aws_iam_role_policy_attachment" "test-policy-AWSCodeCommitFullAccess" {
policy_arn = "arn:aws:iam::aws:policy/AWSCodeCommitFullAccess"
role = "${aws_iam_role.toolchain-role.name}"
}
You can add other managed policies one by one.
If you want to do together, you can try below code
variable "managed_policies" {
default = ["arn:aws:iam::aws:policy/AWSCodeCommitFullAccess",
"arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess",
"arn:aws:iam::aws:policy/AWSCodeDeployFullAccess",
"arn:aws:iam::aws:policy/AWSCodePipelineFullAccess",
]
}
resource "aws_iam_role_policy_attachment" "tc-role-policy-attach" {
count = "${length(var.managed_policies)}"
policy_arn = "${element(var.managed_policies, count.index)}"
role = "${aws_iam_role.toolchain-role.name}"
}

In identity server 3 how to relate user to client

I am using Identity Server 3. I have couple applications ie. Client configured and have few users configured. How do i establish the relationship between User and a Client and also view all applications that the selected User has access to.
Update 1
I am sorry if question was confusing. On IdSvr3 home page, there is a link to revoke application permissions. I am guessing in order to revoke the permission you have to first establish the relationship between user and application.
and i wanted to know how to establish that permission when i add new user?
There's no direct way to limit one or multiple users to a certain client. This is where you should think about implementing your own custom validation. Fortunately, the IdentityServer provides an extensibility point for this kind of requirement.
ICustomRequestValidator
You should implement this interface to further validate users to see if they belong to certain clients and filter them out. You can look into the user details by looking at ValidatedAuthorizeRequest.Subject. This custom validator will start after validating optional parameters such as nonce, prompt, arc_values ( AuthenticationContextReference ), login_hint, and etc. The endpoint is AuthorizeEndPointController and the default implementation of the interface for the tailored job is AuthorizeRequestValidator and its RunValidationAsync. You should take a look at the controller and the class.
Implementation tip
By the time the custom request validation begins, a Client reference will be presented in ValidatedAuthorizeRequest. So all you need to do would be matching the client id or some other identifiers you think you need to verify the client. Probably, you might want to add a Claim key-value pair to your client which you want to allow a few users.
Maybe something like this.
new InMemoryUser{Subject = "870805", Username = "damon", Password = "damon",
Claims = new Claim[]
{
new Claim(Constants.ClaimTypes.Name, "Damon Jeong"),
new Claim(Constants.ClaimTypes.Email, "dmjeong#email.com"),
new Claim(Constants.ClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean)
}
}
Assume you have above user, then add the subject id to the claim of a client like below.
new Client
{
ClientName = "WPF WebView Client Sample",
ClientId = "wpf.webview.client",
Flow = Flows.Implicit,
.
.
.
// Add claim for limiting this client to certain users.
// Since a claim only accepts type and value as string,
// You can add a list of subject id by comma separated values
// eg ( new Claim("BelongsToThisUser", "870805, 870806, 870807") )
Claims = new List<Claim>
{
new Claim("BelongsToThisUser", "870805")
}
},
And then just implement the ICustomRequestValidator and try to match the Claim value with the given user in its ValidateAuthorizeRequestAsync.
public class UserRequestLimitor : ICustomRequestValidator
{
public Task<AuthorizeRequestValidationResult> ValidateAuthorizeRequestAsync(ValidatedAuthorizeRequest request)
{
var clientClaim = request.Client.claims.Where(x => x.Type == "BelongsToThisUser").FirstOrDefault();
// Check is this client has "BelongsToThisUser" claim.
if(clientClaim != null)
{
var subClaim = request.Subject.Claims.Where(x => x.Type == "sub").FirstOrDefault() ?? new Claim(string.Empty, string.Empty);
if(clientClaim.Value == userClaim.Value)
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
IsError = false
});
}
else
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
ErrorDescription = "This client doesn't have an authorization to request a token for this user.",
IsError = true
});
}
}
// This client has no access controls over users.
else
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
IsError = false
});
}
}
public Task<TokenRequestValidationResult> ValidateTokenRequestAsync(ValidatedTokenRequest request)
{
// your implementation
}
}
Time to DI
You need to inject your own dependency when you configure up your IdentityServer. The authorization server uses IdentityServerServiceFactory for registering dependencies.
var factory = new IdentityServerServiceFactory();
factory.Register(new Registration<ICustomRequestValidator>(resolver => new UserRequestLimitor()));
Then Autofac; the IoC container in IdentityServer will do the rest of the DI jobs for you.

Get SharePoint group permissions level name based on group name Using SharePoint Rest API

I am trying to get SharePoint User group permissions (Ex: Read, Contribute) based on the group name using SharePoint Rest API. My goal is to get the permission level of the group and disable features on our custom app based on the permission levels. I have tried the below url to get the group properties but couldn't get the permission level of the group. Could anyone please guide me on how to get the User group permissions.
Options Tried:
URL = http://Servename/Site/api/web/SiteGroups/getByName('group name')
You won't be able to get this from the SiteGroup object alone. Your rest-call only retrieves group information (title, id, description and other metadata). To retrieve permission levels you will need to do a couple of more calls.
See https://msdn.microsoft.com/en-us/library/office/dn531432.aspx to read more about RoleAssignment and RoleDefinition
The function below returns Group Permission Level title and rest of the information:
function init() {
clientContext = new SP.ClientContext.get_current();
oWeb = clientContext.get_web();
currentUser = oWeb.get_currentUser();
allGroups = currentUser.get_groups();
clientContext.load(allGroups);
clientContext.executeQueryAsync(OnSuccess, OnFailure);
function OnSuccess() {
var grpsEnumerator = allGroups.getEnumerator();
while (grpsEnumerator.moveNext()) {
var group = grpsEnumerator.get_current();
var grpTitle = group.get_title();
var grpid = group.get_id();
console.log('Group Id :' + grpid);
console.log('Group Title :'+ grpTitle);
roleBindings = oWeb.get_roleAssignments().getByPrincipalId(grpid).get_roleDefinitionBindings();
clientContext.load(roleBindings);
clientContext.executeQueryAsync(function () {
var iterator = roleBindings.getEnumerator();
while (iterator.moveNext()) {
current = iterator.get_current();
console.log('Show Role Defination Title : '+ current.get_name());
}
});
}
}
function OnFailure(){
console.log('Process Failed');
}
}