Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support rbac v2 statements #157

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/internal/meta/operation/rbac_statement.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ fragment RbacStatement on RbacStatement {
all
}
role
version
}

mutation createRbacStatement($config: RbacStatementInput!) {
Expand Down
32 changes: 32 additions & 0 deletions client/internal/meta/schema/rbac.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ extend type Query {
"""
rbacStatements: [RbacStatement!]!


"""
Get all RBAC Role Statements
"""
rbacRoleStatements: [RbacStatement!]!

"""
Get all RBAC resource statements for a particular object
"""
rbacResourceStatement(id: ObjectId!): [RbacStatement!]!

"""
Given a particular user, and a particular object/role request, return what would happen.
Note that we assume that the customer owning the object is the current
Expand Down Expand Up @@ -66,6 +77,11 @@ extend type Query {
Get the group users will be assigned to by default
"""
rbacDefaultGroup: RbacGroup!

"""
Get the group users will be assigned to by default
"""
rbacDefaultSharingGroups: [RbacDefaultSharingGroup!]!
}

extend type User {
Expand Down Expand Up @@ -116,6 +132,8 @@ extend type Mutation {
"""
setRbacDefaultGroup(id: ORN!): ResultStatus!
unsetRbacDefaultGroup: ResultStatus!

setRbacDefaultSharingGroups(shares: [RbacDefaultSharingGroupInput!]): ResultStatus!
}

scalar ORN @goModel(model: "observe/authorization/id.ORN")
Expand Down Expand Up @@ -212,6 +230,8 @@ type RbacStatement implements AuditedObject @goModel(model: "observe/rbac/policy
object: RbacObject!
role: RbacRole!

version: Int

createdBy: UserId!
createdByInfo: UserInfo! @goField(forceResolver: true)
createdDate: Time!
Expand All @@ -225,6 +245,7 @@ input RbacStatementInput @goModel(model: "observe/rbac/policy.Statement") {
subject: RbacSubjectInput!
object: RbacObjectInput!
role: RbacRole!
version: Int
}

input UpdateRbacStatementInput @goModel(model: "observe/rbac/policy.Statement") {
Expand All @@ -233,6 +254,7 @@ input UpdateRbacStatementInput @goModel(model: "observe/rbac/policy.Statement")
subject: RbacSubjectInput!
object: RbacObjectInput!
role: RbacRole!
version: Int
}

type MutateRbacStatementsResponse @goModel(model: "observe/meta/metatypes.MutateRbacStatementsResponse") {
Expand All @@ -241,6 +263,16 @@ type MutateRbacStatementsResponse @goModel(model: "observe/meta/metatypes.Mutate
deletedStatements: [ORN!]!
}

type RbacDefaultSharingGroup @goModel(model: "observe/meta/metatypes.RbacDefaultSharingGroup") {
groupId: ORN!
allowEdit: Boolean!
}

input RbacDefaultSharingGroupInput @goModel(model: "observe/meta/metatypes.RbacDefaultSharingGroup") {
groupId: ORN!
allowEdit: Boolean!
}

"""
A RequestSubject is different from a Subject, because the RequestSubject
provides all of the values, such that each Statement can match against
Expand Down
11 changes: 11 additions & 0 deletions client/meta/genqlient.generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/resources/rbac_statement.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ resource "observe_rbac_statement" "group_example" {
### Optional

- `description` (String)
- `version` (Number)

### Read-Only

Expand Down
17 changes: 17 additions & 0 deletions observe/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,23 @@ func validateStringInSlice(valid []string, ignoreCase bool) schema.SchemaValidat
}
}

func validateInSlice[T comparable](valid []T) schema.SchemaValidateDiagFunc {
return func(i interface{}, path cty.Path) diag.Diagnostics {
t, ok := i.(T)
if !ok {
return diag.Errorf("expected type of %s to be %T", i, t)
}

for _, v := range valid {
if t == v {
return nil
}
}

return diag.Errorf("expected %v to be one of %v", t, i)
}
}

func validateTimeDuration(i interface{}, path cty.Path) diag.Diagnostics {
s := i.(string)
if _, err := time.ParseDuration(s); err != nil {
Expand Down
91 changes: 62 additions & 29 deletions observe/resource_rbac_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,12 @@ const (
schemaRbacStatementObjectTypeDescription = "The type of object such as dataset."
schemaRbacStatementObjectNameDescription = "The name of object. Can be provided along with `type`."
schemaRbacStatementObjectOwnerDescription = "True to bind to objects owned by the user. Can be provided along with `type`."
schemaRbacStatementVersionDescription = "The version of the statement. Defaults to V1"

schemaRbacStatementSubjectUserDescription = "OID of a user."
schemaRbacStatementSubjectGroupDescription = "OID of a RBAC Group."
)

var rbacStatementObjectTypes = []string{
"object.0.id",
"object.0.folder",
"object.0.workspace",
"object.0.type",
"object.0.all",
}

func resourceRbacStatement() *schema.Resource {
return &schema.Resource{
Description: "Manages a RBAC Statement.",
Expand Down Expand Up @@ -86,25 +79,21 @@ func resourceRbacStatement() *schema.Resource {
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
ExactlyOneOf: rbacStatementObjectTypes,
Optional: true,
Description: schemaRbacStatementObjectIdDescription,
},
"folder": {
Type: schema.TypeString,
ExactlyOneOf: rbacStatementObjectTypes,
Optional: true,
Description: schemaRbacStatementObjectFolderDescription,
},
"workspace": {
Type: schema.TypeString,
ExactlyOneOf: rbacStatementObjectTypes,
Optional: true,
Description: schemaRbacStatementObjectWorkspaceDescription,
},
"type": {
Type: schema.TypeString,
ExactlyOneOf: rbacStatementObjectTypes,
Optional: true,
Description: schemaRbacStatementObjectTypeDescription,
},
Expand All @@ -123,7 +112,6 @@ func resourceRbacStatement() *schema.Resource {
},
"all": {
Type: schema.TypeBool,
ExactlyOneOf: rbacStatementObjectTypes,
Optional: true,
Default: false,
},
Expand All @@ -135,6 +123,12 @@ func resourceRbacStatement() *schema.Resource {
Required: true,
ValidateDiagFunc: validateEnums(gql.AllRbacRoles),
},
"version": {
Type: schema.TypeInt,
Optional: true,
Default: 1,
ValidateDiagFunc: validateInSlice([]int{1, 2}),
},
"oid": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -150,13 +144,22 @@ func newRbacStatementConfig(data *schema.ResourceData) (input *gql.RbacStatement
input.Description = v.(string)
}

var version int
if v, ok := data.GetOk("version"); ok {
version = v.(int)
// we only care about setting the version field if it's V2
if version == 2 {
input.Version = &version
}
}

subject, err := newRbacSubjectInput(data)
if err != nil {
return nil, diag.Errorf(err.Error())
}
input.Subject = subject

object, err := newRbacObjectInput(data)
object, err := newRbacObjectInput(data, version)
if err != nil {
return nil, diag.Errorf(err.Error())
}
Expand Down Expand Up @@ -186,24 +189,36 @@ func newRbacSubjectInput(data *schema.ResourceData) (gql.RbacSubjectInput, error
return subject, nil
}

func newRbacObjectInput(data *schema.ResourceData) (gql.RbacObjectInput, error) {
func newRbacObjectInput(data *schema.ResourceData, version int) (gql.RbacObjectInput, error) {
object := gql.RbacObjectInput{}
if v, ok := data.GetOk("object.0.id"); ok {
object.ObjectId = stringPtr(v.(string))
}
if v, ok := data.GetOk("object.0.folder"); ok {
if version == 2 {
return object, fmt.Errorf("object.folder is not supported in V2 statements")
}
object.FolderId = stringPtr(v.(string))
}
if v, ok := data.GetOk("object.0.workspace"); ok {
if version == 2 {
return object, fmt.Errorf("object.workspace is not supported in V2 statements")
}
object.WorkspaceId = stringPtr(v.(string))
}
if v, ok := data.GetOk("object.0.type"); ok {
object.Type = stringPtr(v.(string))
if oname, ok := data.GetOk("object.0.name"); ok {
if version == 2 {
return object, fmt.Errorf("object.name is not supported in V2 statements")
}
object.Name = stringPtr(oname.(string))
}
}
object.Owner = boolPtr(data.Get("object.0.owner").(bool))
if version == 2 && *object.Owner {
return object, fmt.Errorf("object.owner is not supported in V2 statements")
}
object.All = boolPtr(data.Get("object.0.all").(bool))
return object, nil
}
Expand Down Expand Up @@ -284,22 +299,32 @@ func rbacStatementToResourceData(r *gql.RbacStatement, data *schema.ResourceData

// object
object := make(map[string]interface{}, 0)
if r.Object.ObjectId != nil {
object["id"] = *r.Object.ObjectId
} else if r.Object.FolderId != nil {
object["folder"] = *r.Object.FolderId
} else if r.Object.WorkspaceId != nil {
object["workspace"] = *r.Object.WorkspaceId
} else if r.Object.Type != nil {
object["type"] = *r.Object.Type
if r.Object.Name != nil {
object["name"] = *r.Object.Name
if r.Version != nil && *r.Version == 2 {
// RBAC v2 statements will have an id AND a type for resource statements, and neither for role statements
if r.Object.ObjectId != nil {
object["id"] = *r.Object.ObjectId
}
if r.Object.Owner != nil {
object["owner"] = *r.Object.Owner
if r.Object.Type != nil {
object["type"] = *r.Object.Type
}
} else {
if r.Object.ObjectId != nil {
object["id"] = *r.Object.ObjectId
} else if r.Object.FolderId != nil {
object["folder"] = *r.Object.FolderId
} else if r.Object.WorkspaceId != nil {
object["workspace"] = *r.Object.WorkspaceId
} else if r.Object.Type != nil {
object["type"] = *r.Object.Type
if r.Object.Name != nil {
object["name"] = *r.Object.Name
}
if r.Object.Owner != nil {
object["owner"] = *r.Object.Owner
}
} else if r.Object.All != nil {
object["all"] = *r.Object.All
}
} else if r.Object.All != nil {
object["all"] = *r.Object.All
}
if err := data.Set("object", []interface{}{object}); err != nil {
diags = append(diags, diag.FromErr(err)...)
Expand All @@ -310,6 +335,14 @@ func rbacStatementToResourceData(r *gql.RbacStatement, data *schema.ResourceData
diags = append(diags, diag.FromErr(err)...)
}

version := 1
if r.Version != nil {
version = *r.Version
}
if err := data.Set("version", version); err != nil {
diags = append(diags, diag.FromErr(err)...)
}

if err := data.Set("oid", r.Oid().String()); err != nil {
diags = append(diags, diag.FromErr(err)...)
}
Expand Down
Loading
Loading