I created a custom role that consists of some permission but when I tried to attach it to service account or container programatically it always give error. Is it not supported yet? If it is supported how can I attach it to service account or container?
My code are as follow:
In Google Cloud Storage
Policy policy = storage.getIamPolicy(bucketName);
Policy updatedPolicy = storage.setIamPolicy(bucketName, policy.toBuilder().addIdentity(Role.of("roles/CustomRole341"), Identity.serviceAccount(emailServiceAccount)).build());
ServiceAccount user = findServiceAccount(iam, username, projectName);
List<String> member = new ArrayList<String>();
member.add(Identity.serviceAccount(user.getEmail()).toString());
Binding s = new Binding();
s.setRole("roles/CustomRole341");
s.setMembers(member);
List<Binding> bindings = new ArrayList<Binding>();
bindings.add(s);
Policy a = new Policy();
a.setBindings(bindings);
SetIamPolicyRequest req = new SetIamPolicyRequest();
req.setPolicy(a);
iam.projects().serviceAccounts().setIamPolicy("projects/" + projectName + "/serviceAccounts/" + username + "@" + projectName + ".iam.gserviceaccount.com" , req).execute()
@ihsanhaikalz What is the error that you get?
@lesv Do you know off-hand the correct way to do this?
@vchudnov-g here is the error that I got
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Role roles/CustomRole341 is not supported for this resource.",
"reason" : "badRequest"
} ],
"message" : "Role roles/CustomRole341 is not supported for this resource.",
"status" : "INVALID_ARGUMENT"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at gcp.GoogleIAM.testSetRoleToServiceAccount(GoogleIAM.java:236)
at gcp.GoogleIAM.main(GoogleIAM.java:73)
I am not sure whether the naming of the role is correct by using roles/CustomRole341 because I tried to follow other roles like roles/storage.admin.
@ihsanhaikalz Is CustomRole341 defined? Did you go through the procedure in https://cloud.google.com/iam/docs/creating-custom-roles#creating_a_custom_role to create it before trying to use it? Do you get the same error if you use one of the pre-defined roles?
@ihsanhaikalz Where are you running this?
@jabubake PTAL
In general, default service accounts are provided to GCP and GAE to run your code, you need to add whatever scope is needed beyond the https://www.googleapis.com/auth/cloud-platform scope to your default service account using Cloud Console IAM & admin > IAM
You can also provide a custom service account json file and use that instead of the default credential provider to do auth.
--
I have this exact problem too!
# Add the temporary K8 discovery project
resource "google_project" "k8-discovery" {
name = "at-k8-discovery"
project_id = "k8-discovery-185615"
billing_account = "${local.billing_account_id}"
folder_id = "${google_folder.delivery-engineering.name}"
}
resource "google_project_iam_custom_role" "container-registry-viewer" {
role_id = "container.registry.viewer"
title = "Container Registry Viewer"
description = "Enables someone to view/pull from the GCR"
permissions = ["storage.objects.get", "storage.objects.list"]
}
resource "google_project_iam_policy" "project" {
project = "${google_project.k8-discovery.project_id}"
policy_data = "${data.google_iam_policy.k8-policy.policy_data}"
}
data "google_iam_policy" "k8-policy" {
binding {
role = "roles/container.registry.viewer"
error is googleapi: Error 400: Role roles/container.registry.viewer is not supported for this resource., badRequest
@frankyn : Frank, can you take a look at the code snippet provided in the initial post?
FYI I worked around this by specifying a fully qualified role - see https://github.com/terraform-providers/terraform-provider-google/issues/993
Just updating here too- I posted in https://github.com/terraform-providers/terraform-provider-google/issues/993 that the reason this is happening is that the name of custom roles has to be in the form projects/{project-id}/roles/{role-id}- omitting the project will cause it to fail, just as it would fail if you typo-ed the name of the role.
Thanks @danawillow and @Stono, I tried using the correct Role resource form with the client and I'm still seeing the same issue. Reviewing implementation of class Role, the Rule.of() expects roles prefixed with roles/ which doesn't fit the pattern for Custom Roles.
Sorry for the late reply.
@lesv I run this using google-cloud-storage version 1.12.0 and google-api-services-iam v1-rev220-1.23.0
@vchudnov-g I created the custom role from the Console as well as from the IAM Java API using something like this
public static Role createCustomRole(Iam iam, String roleTitle, String roleId, List<String> permission, String description, String projectName) throws IOException{
Role role = new Role();
role.setTitle(roleTitle);
role.setDescription(description);
role.setIncludedPermissions(permission);
CreateRoleRequest req = new CreateRoleRequest();
req.setRoleId(roleId);
req.setRole(role);
return iam.projects().roles().create("projects/"+projectName, req).execute();
}
private static Role testCreateCustomRole(Iam iam) throws IOException{
Role role = new Role();
role.setTitle("testTitle");
List<String> permissions = new ArrayList<>();
permissions.add("storage.buckets.create");
permissions.add("storage.buckets.delete");
role.setDescription("testing create role 1");
role.setIncludedPermissions(permissions);
CreateRoleRequest req = new CreateRoleRequest();
req.setRoleId("testID");
req.setRole(role);
return iam.projects().roles().create("projects/"+PROJECT_NAME, req).execute();
}
Assigning the service account with pre-defined roles gave no error but with custom role gave error. I am not sure if what I did was right or wrong, especially with the naming I just gave simple name like CustomRole341.
@danawillow @Stono @frankyn So what do you think is the best approach to assign custom role using Java API? I don't think I could specify roles using the format projects/{project-id}/roles/{role-id} as it only accepts Role.of(the role ID or stuff)
UPDATES
So I tried to assign the custom role for Google IAM and it works as per suggested by @danawillow @Stono @frankyn something like this:
setRoleToServiceAccount(iam, PROJECT_NAME, "cfb-employee-ihsan", "projects/testing-123-ok/roles/AdministratorCfB" );
....
public static Policy setRoleToServiceAccount(Iam iam, String projectName, String username, String role) throws IOException{
ServiceAccount user = findServiceAccount(iam, username, projectName);
List<String> member = new ArrayList<String>();
member.add(Identity.serviceAccount(user.getEmail()).toString());
Binding binding = new Binding();
binding.setRole(role);
binding.setMembers(member);
List<Binding> bindings = new ArrayList<Binding>();
bindings.add(binding);
Policy policy = new Policy();
policy.setBindings(bindings);
SetIamPolicyRequest req = new SetIamPolicyRequest();
req.setPolicy(policy);
return iam.projects().serviceAccounts().setIamPolicy("projects/" + projectName + "/serviceAccounts/" + username + "@" + projectName + ".iam.gserviceaccount.com" , req).execute();
}
But for the Storage to assign custom role into the Bucket still gives me error of:
Exception in thread "main" com.google.cloud.storage.StorageException: Invalid argument
at com.google.cloud.storage.spi.v1.HttpStorageRpc.translate(HttpStorageRpc.java:189)
at com.google.cloud.storage.spi.v1.HttpStorageRpc.setIamPolicy(HttpStorageRpc.java:888)
at com.google.cloud.storage.StorageImpl$36.call(StorageImpl.java:924)
at com.google.cloud.storage.StorageImpl$36.call(StorageImpl.java:921)
at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:89)
at com.google.cloud.RetryHelper.run(RetryHelper.java:74)
at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:51)
at com.google.cloud.storage.StorageImpl.setIamPolicy(StorageImpl.java:921)
at gcp.GoogleStorage.setBucketRoleAndServiceAccount(GoogleStorage.java:84)
at gcp.GoogleStorage.main(GoogleStorage.java:41)
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid argument",
"reason" : "invalid"
} ],
"message" : "Invalid argument"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at com.google.cloud.storage.spi.v1.HttpStorageRpc.setIamPolicy(HttpStorageRpc.java:886)
... 8 more
with the code like:
setBucketRoleAndServiceAccount(a, "testagainoioi", "[email protected]", Role.of("projects/testing-123-ok/roles/DeveloperCfB"));
...
public static void setBucketRoleAndServiceAccount(Storage storage, String bucketName, String emailServiceAccount, Role role){
Policy policy = storage.getIamPolicy(bucketName);
Policy updatedPolicy = storage.setIamPolicy(bucketName,
policy.toBuilder().addIdentity(role, Identity.serviceAccount(emailServiceAccount)).build());
if (updatedPolicy.getBindings().get(role).contains(Identity.serviceAccount(emailServiceAccount))) {
System.out.printf("Added %s with role %s to %s\n", Identity.serviceAccount(emailServiceAccount), role.getValue(), bucketName);
}
else{
System.out.println("Something is wrong!");
}
}
but assigning pre-defined roles is fine like this:
setBucketRoleAndServiceAccount(a, "testagainoioi", "[email protected]", StorageRoles.admin());
Any idea how to fix assigning Role to Bucket?
@pongad could you update to this issue once your commit has been pushed to master? hopefully your commit could solve my issue
Just updating here too- I posted in terraform-providers/terraform-provider-google#993 that the reason this is happening is that the name of custom roles has to be in the form
projects/{project-id}/roles/{role-id}- omitting the project will cause it to fail, just as it would fail if you typo-ed the name of the role.
Actually, I get this error and forward slash is an invalid character:
ERROR: (gcloud.iam.roles.create) INVALID_ARGUMENT: The role_id "projects/project/roles/my_role" is invalid. It doesn't match pattern "[a-zA-Z0-9_\.]{3,64}". The role_id must be 3 to 64 characters long and can be a mix of uppercase and lowercase English letters, digits, underscores and periods.
Most helpful comment
Just updating here too- I posted in https://github.com/terraform-providers/terraform-provider-google/issues/993 that the reason this is happening is that the name of custom roles has to be in the form
projects/{project-id}/roles/{role-id}- omitting the project will cause it to fail, just as it would fail if you typo-ed the name of the role.