Hi Team, how to create resource policy using golan...
# help
a
Hi Team, how to create resource policy using golang sdk?
d
Hi, you can use
func (c *GRPCAdminClient) AddOrUpdatePolicy(ctx context.Context, policies *PolicySet) error
method. https://pkg.go.dev/github.com/cerbos/cerbos-sdk-go/cerbos#GRPCAdminClient.AddOrUpdatePolicy
Here’s a link to the example section
a
Thank you @Dennis (Cerbos)
one more doubt is there
When a pod starts up, it registers a policy. But if the pod restarts, it tries to register the policy again. How can we deal with this problem?
d
The pod can check if the policy is already registered first. I assume you can’t use a disk/git storage because you have other dynamic policies.
I was thinking if you could use the “overlay” storage, but I don’t think it fits your use case
a
we use mysql @Dennis (Cerbos)
d
Did you try to use GetPolicy to check if the policy is registered?
I remember you tried it with
ListPolicies
and had a question about policy IDs. Did you have any luck with that?
a
for external services registration can we use yaml file? is there anything available?
d
Can you please provide more details about this scenario? I am not sure what you mean by external services registration.
a
we have designed a IAM application for our internal purposes. in that we use cerbos for authorization. we are using the resource policy.in this resource policy the resource will be the full method name of the rpcs we have in our grpc application and we use roles and permissions or actions. this policies we need to register. we want this to be registered somehow. we use mysql db for our cerbos. am confused with adding it using yaml. is that possible. @Dennis (Cerbos)
d
I see. You need to add these policies to the mysql db. You said that when the pod restarts it tries to register the policy again. Can you please describe why this is a problem?
In my view, the (restarting) pod will try to update the policy, but since there’s no change in the policies the operation will have no effect.
a
so it means if new policy added then no problem even if pod restart it will update already exist policy only so no problem right?
d
Correct. The API updates the policy if the policy ID remains the same.
If the policy is unchanged, it means the policy ID is also unchanged.
a
this is yaml i use
Copy code
- resourceName: "ActionService-Action-ListActions"
    actions:
      - "org_mgmt"
      - "role_mgmt"
      - "user_mgmt"
this is how i read it
Copy code
func readConfig(config *domain.Policies) error {
	fileLocation := os.Getenv("RESOURCE_POLICY_FILE_LOCATION")
	if fileLocation == "" {
		fileLocation = "/etc/policy/resourcepolicy.yaml"
	}
	if _, err := os.Stat(fileLocation); os.IsNotExist(err) {
		return fmt.Errorf("config file %s does not exist", fileLocation)
	}
	file, err := os.Open(fileLocation)
	if err != nil {
		return fmt.Errorf("error opening config file %s: %v", fileLocation, err)
	}
	defer file.Close()
	decoder := yaml.NewDecoder(file)
	if err := decoder.Decode(config); err != nil {
		return fmt.Errorf("error decoding config file %s: %v", fileLocation, err)
	}
	fmt.Println(config.Policies)
	return nil
}
this is how i add policy,
Copy code
func (c *Client) AddOrUpdateCerbosResourcePolicy(resourceName string, actions []string) error {
	<http://c.log.Info|c.log.Info>("AddOrUpdateCerbosResourcePolicy invoked")
	defer <http://c.log.Info|c.log.Info>("AddOrUpdateCerbosResourcePolicy exited")
	policy := client.NewResourcePolicy(resourceName, "default").
		AddResourceRules(
			client.NewAllowResourceRule("*"). 
								WithRoles(actions...),
		)
	if err := c.CerbosAdminClient.AddOrUpdatePolicy(context.Background(), cerbosclient.NewPolicySet().AddResourcePolicies(policy)); err != nil {
		return fmt.Errorf("error occured while add or update policy - Error %s", err.Error())
	}
	return nil
}
register
Copy code
func (c *Client) RegisterIAMResourcePolicies() error {
	<http://c.log.Info|c.log.Info>("RegisterIAMResourcePolicies invoked")
	defer <http://c.log.Info|c.log.Info>("RegisterIAMResourcePolicies exited")
	var policies domain.Policies
	if err := readConfig(&policies); err != nil {
		return fmt.Errorf("error reading config: %v", err)
	}
	for _, policy := range policies.Policies {
		if err := c.AddOrUpdateCerbosResourcePolicy(policy.ResourceName, policy.Actions); err != nil {
			return fmt.Errorf("error registering policy for resource %s: %v", policy.ResourceName, err)
		}
	}
	return nil
}
if remove some policy how can i handle it, like disabling it? @Dennis (Cerbos)
👍 1
Copy code
package domain

type CerbosResourcePolicy struct {
	ResourceName string   `yaml:"resourceName"`
	Actions      []string `yaml:"actions"`
}

type Policies struct {
	Policies []CerbosResourcePolicy `yaml:"policies"`
}
d
You need to know the ID of a policy to disable it. Keeping track of policies one needs to disable is a bit tedious. I’ll double-check if you could use an “overlay” storage. It would be great if these policies could be read from disk storage and others from mysql. Edit: Overlay storage can’t help here.
c
The ID of a policy is determined by its kind (principal, resource, derived roles), name (e.g. resource name), version and scope. If you add a resource policy with the same kind, name, version and scope using the
AddOrUpdatePolicy
Admin API endpoint, it would overwrite the existing policy. This also means that if you keep adding the same policy definition over and over again, it's effectively idempotent.
If you list your policies using
ListPolicies
the items will look like
resource.invoice.vdefault/foo.bar
. So, if you know the kind, name, version and scope of a policy already, you can construct the ID with something like:
Copy code
fmt.Sprintf("%s.%s.v%s/%s", kind, name, version, scope)
Scope is optional. So if you don't use any scoped policies the ID would simply be:
Copy code
fmt.Sprintf("%s.%s.v%s", kind, name, version)
a
am disable policy like this
Copy code
func Disable() {
	ids := []string{"resource.GreetingsService_SayHello.vdefault",
		"resource.Org_GetOrgByName.vdefault",
		"resource.movie.vdefault",
		"resource.movie_dghgsd_sd.vdefault",
		"resource.movie_object.vdefault",
	}
	_, err := admcli.DisablePolicy(context.Background(), ids...)
	if err != nil {
		fmt.Printf("error disabling policy: %v", err)
	}
}
but getting this error error disabling policy: could not disable policy: rpc error: code = Unimplemented desc = Admin service is disabled by the configuration
Copy code
func ListPolicies() {
	list, err := admcli.ListPolicies(context.Background())
	if err != nil {
		fmt.Printf("error getting lists: %v", err)
	}
	for _, v := range list {
		fmt.Printf(" %s \n", v)
	}
}
o
Admin API needs to be enabled in the cerbos configuration.
Copy code
server:
  adminAPI:
    enabled: true
    adminCredentials: # OPTIONAL
      passwordHash: JDJ5JDEwJEdEOVFzZDE2VVhoVkR0N2VkUFBVM09nalc0QnNZaC9xc2E4bS9mcUJJcEZXenp5OUpjMi91Cgo= # PasswordHash is the base64-encoded bcrypt hash of the password to use for authentication.
      username: cerbos # Username is the hardcoded username to use for authentication.
See Full Configuration page for more details.
a
@oguzhan
Copy code
server:
  httpListenAddr: ":3592"
  grpcListenAddr: ":3593"
  #grpcListenAddr: "unix:/tmp/sock/cerbos.grpc"
  #httpListenAddr: "unix:/tmp/sock/cerbos.http"
  #udsFileMode: 0o766
  adminAPI:
    adminCredentials:
      passwordHash: JDJ5JDEwJGJWcFRKUzJKRzYxOTJERWs5SzZaS2VSb2Z1cXNSeTYzam9NR1U5UkVKM3BtZ1VLQUVuM0xlCgo= # echo "randomHash" | htpasswd -niBC 10 cerbos | cut -d ':' -f 2 | base64
      username: cerbos
    enabled: true
already its enabled only
c
My hunch is that Cerbos is using the default configuration and not reading your configuration file. You can verify this by looking at the logs when Cerbos starts. It'll print out which configuration file it's reading.
a
@Charith (Cerbos)
Copy code
cerbos:
        container_name: cerbos
        image: <http://ghcr.io/cerbos/cerbos:latest|ghcr.io/cerbos/cerbos:latest>
        restart: always
        command: ['server', '--config=/config/conf.yaml', '--log-level=warn']
        volumes:
            - ./config:/config
        depends_on:
            - database
        ports:
            - 3592:3592
            - 3593:3593
        networks:
            - intranet
created a folder named config , inside it created a file named conf.yaml
@Charith (Cerbos)
Copy code
2023-09-21 14:36:26 {"log.level":"info","@timestamp":"2023-09-21T09:06:26.488Z","log.logger":"cerbos.server","message":"maxprocs: Leaving GOMAXPROCS=4: CPU quota undefined"}
2023-09-21 14:36:26 {"log.level":"info","@timestamp":"2023-09-21T09:06:26.489Z","log.logger":"cerbos.server","message":"Loading configuration from /config/conf.yaml"}
2023-09-21 14:36:26 {"log.level":"info","@timestamp":"2023-09-21T09:06:26.500Z","log.logger":"cerbos.auditlog","message":"Initializing audit log","backend":"local","path":"/auditlogs"}
2023-09-21 14:36:26 {"log.level":"info","@timestamp":"2023-09-21T09:06:26.525Z","log.logger":"cerbos.mysql","message":"Initializing MySQL storage"}
2023-09-21 14:36:28 {"log.level":"info","@timestamp":"2023-09-21T09:06:28.194Z","log.logger":"cerbos.telemetry","message":"Anonymous telemetry enabled. Disable via the config file or by setting the CERBOS_NO_TELEMETRY=1 environment variable"}
2023-09-21 14:36:28 {"log.level":"info","@timestamp":"2023-09-21T09:06:28.195Z","log.logger":"cerbos.grpc","message":"Starting admin service"}
2023-09-21 14:36:28 {"log.level":"info","@timestamp":"2023-09-21T09:06:28.196Z","log.logger":"cerbos.grpc","message":"Starting gRPC server at :3593"}
2023-09-21 14:36:28 {"log.level":"info","@timestamp":"2023-09-21T09:06:28.196Z","log.logger":"cerbos.http","message":"Starting HTTP server at :3592"}
Copy code
{
  "log.level": "error",
  "@timestamp": "2023-09-21T09:08:44.831Z",
  "log.logger": "cerbos.grpc",
  "message": "Handled request",
  "grpc.start_time": "2023-09-21T09:08:44Z",
  "grpc.request.deadline": "2023-09-21T09:08:46Z",
  "system": "grpc",
  "span.kind": "server",
  "grpc.service": "cerbos.svc.v1.CerbosAdminService",
  "grpc.method": "DisablePolicy",
  "peer.address": "172.24.0.1:59122",
  "error": "rpc error: code = Unimplemented desc = Admin service is disabled by the configuration",
  "grpc.code": "Unimplemented",
  "grpc.time_ms": 0.194
}
c
Hmm... very strange. What's the version of Cerbos you're on?
And does it happen when you make other Admin API calls?
a
cerbos:0.24.0
c
That's quite an old version. Could you try with the latest (0.30.0) please.
a
for adding policy also i used admin api,it worked
Copy code
func AddResourcePolicy() {
	policy := client.NewResourcePolicy("ActionService-Action-CreateAction", "default").
		AddResourceRules(
			client.NewAllowResourceRule("org_mgmt", "role_mgmt", "user_mgmt").
				WithRoles("a"),
		)
	if err := admcli.AddOrUpdatePolicy(context.Background(), client.NewPolicySet().AddResourcePolicies(policy)); err != nil {
		fmt.Printf("error occured while add or update policy - Error %s", err.Error())
		return
	}
}
only while disable it showed me error
o
I think it is because 0.24.0 doesn’t have the
DisablePolicy
.
c
Indeed!
We should make that error message better. @ANILA SOMAN please try with
<http://ghcr.io/cerbos/cerbos:0.30.0|ghcr.io/cerbos/cerbos:0.30.0>
as I suggested above.
1
a
Copy code
package main

import (
	"context"
	"fmt"
	"log"

	"<http://github.com/cerbos/cerbos/client|github.com/cerbos/cerbos/client>"
)

const (
	username = "cerbos"
	password = "randomHash"
)

var admcli client.AdminClient
var cli client.Client
var err error

const cerbosAddress = "localhost:3592"

func main() {
	admcli, err = client.NewAdminClientWithCredentials(cerbosAddress, username, password, client.WithPlaintext())
	if err != nil {
		log.Fatalf("Failed to create Cerbos client: %v", err)
	}
	cli, err = client.New(cerbosAddress, client.WithPlaintext())
	if err != nil {
		log.Fatalf("Failed to create Cerbos client: %v", err)
	}
	AddResourcePolicy()
	IsPrincipalAllowed()
	ListPoliciesAndDisable()
	IsPrincipalAllowed()
}

func AddResourcePolicy() {
	policy := client.NewResourcePolicy("ActionService-Action-CreateAction", "default").
		AddResourceRules(
			client.NewAllowResourceRule("org_mgmt", "role_mgmt", "user_mgmt").
				WithRoles("a"),
		)
	if err := admcli.AddOrUpdatePolicy(context.Background(), client.NewPolicySet().AddResourcePolicies(policy)); err != nil {
		fmt.Printf("error occured while add or update policy - Error %s", err.Error())
		return
	}
}

func IsPrincipalAllowed() {
	actions := []string{"org_mgmt", "role_mgmt", "user_mgmt"}
	principal := client.NewPrincipal("useremail", "a")
	resource := client.NewResource("ActionService-Action-CreateAction", "useremail")
	allowed := false
	for _, action := range actions {
		allowed, err = cli.IsAllowed(context.Background(), principal, resource, action)
		if err != nil {
			fmt.Printf("error checking permissions: %v", err)
		}
		if allowed {
			allowed = true
			break
		}
	}
	if allowed {
		fmt.Println("The principal is allowed to perform the action on the resource.")
	} else {
		fmt.Println("The principal is not allowed to perform the action on the resource.")
	}
}

func ListPoliciesAndDisable() {
	list, err := admcli.ListPolicies(context.Background())
	if err != nil {
		fmt.Printf("error getting lists: %v", err)
	}
	for _, v := range list {
		fmt.Printf("disabling %s policy \n", v)
		Disable(v)
	}
}

func ListSceme() {
	list, err := admcli.ListSchemas(context.Background())
	if err != nil {
		fmt.Printf("error getting lists: %v", err)
	}
	for _, v := range list {
		fmt.Printf(" %s \n", v)

	}

}

func Disable(id string) {
	ids := []string{"ActionService-Action-CreateAction"}
	_, err := admcli.DisablePolicy(context.Background(), ids...)
	if err != nil {
		fmt.Printf("error disabling policy: %v", err)
	}
}
go run . The principal is allowed to perform the action on the resource. disabling resource.ActionService_Action_CreateAction.vdefault policy The principal is allowed to perform the action on the resource. @Charith (Cerbos) @oguzhan even after disable the policy it shows allowed to me
am using the mention cerbos:0.30.0 version
o
Copy code
_, err := admcli.DisablePolicy(context.Background(), ids...)
if err != nil {
    fmt.Printf("error disabling policy: %v", err)
}
ID for the policy you want to disable looks wrong. I think you might not be disabling the policy at all. DisablePolicy returns a response struct where you can observe how many policies are disabled.
c
The IDs are hardcoded in your
Disable
function
a
🙌 working fine💃 Thank you so much for your tremendous help! @Charith (Cerbos) @oguzhan @Dennis (Cerbos)
👍 2