* skeleton

* fleshing out

* refactoring

* use sub_op method throughout

* fixes

* no longer just ARM error msgs

* all impls

* graph login fns

* fix normalize_graph_tenant

* app object

* call_azure_graph fn

* more impl

* fixing

* more fixing

* define client obj, wrapping arm and graph

* yet more fixing

* add scope for list_role_assignments

* service principal

* continuing fixups

* can load

* use active bindings to redirect

* add scope arg for list_role_defs

* use objects for roles

* get_role_def working

* add and remove_role_assignment

* rm stray print

* fix remove_role_assignment

* really fix remove_role_assignment

* return df from list_role methods

* add refresh method for client

* testing for rbac

* refresh is function, not active binding

* fixing

* tests working

* resource rbac testing

* test tinkering

* fail if selection provided but doesn't exist

* documenting

* more documenting

* role doc

* move graph to new pkg

* fixing for R cmd check

* rm AzureGraph as suggested

* fixes

* doc tweak

* update news

* rm stray bit

* another stray bit

* use latest RBAC API versions

* use new filter for list_role_defs
This commit is contained in:
Hong Ooi 2019-03-15 19:12:12 +11:00 коммит произвёл GitHub
Родитель 5961b294e6
Коммит c4b969bcf7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
25 изменённых файлов: 885 добавлений и 42 удалений

Просмотреть файл

@ -1,6 +1,6 @@
Package: AzureRMR
Title: Interface to 'Azure Resource Manager'
Version: 2.0.0
Version: 2.0.9000
Authors@R: c(
person("Hong", "Ooi", , "hongooi@microsoft.com", role = c("aut", "cre")),
person("Microsoft", role="cph")
@ -16,12 +16,12 @@ Imports:
AzureAuth,
utils,
httr (>= 1.3),
openssl,
jsonlite,
R6
R6,
uuid
Suggests:
knitr,
testthat,
httpuv
Roxygen: list(markdown=TRUE)
RoxygenNote: 6.1.0.9000
RoxygenNote: 6.1.1

Просмотреть файл

@ -4,6 +4,8 @@ export(AzureR_dir)
export(az_resource)
export(az_resource_group)
export(az_rm)
export(az_role_assignment)
export(az_role_definition)
export(az_subscription)
export(az_template)
export(call_azure_rm)
@ -23,6 +25,8 @@ export(is_empty)
export(is_guid)
export(is_resource)
export(is_resource_group)
export(is_role_assignment)
export(is_role_definition)
export(is_subscription)
export(is_template)
export(is_url)

Просмотреть файл

@ -1,3 +1,7 @@
# AzureRMR 2.0.9000
* This version adds basic support for role-based access control (RBAC) at subscription, resource group and resource level. Add and remove role assignments, and retrieve role definitions. See `?rbac` for more information.
# AzureRMR 2.0.0
## Significant interface changes

Просмотреть файл

@ -2,14 +2,14 @@
#' @importFrom utils modifyList
NULL
utils::globalVariables(c("self", "private"))
.onLoad <- function(libname, pkgname)
{
azure_api_version <- "2018-05-01"
azure_api_mgmt_version <- "2016-09-01"
options(azure_api_version=azure_api_version)
options(azure_api_mgmt_version=azure_api_mgmt_version)
options(azure_api_version="2018-05-01")
options(azure_api_mgmt_version="2016-09-01")
options(azure_roledef_api_version="2018-01-01-preview")
options(azure_roleasn_api_version="2018-12-01-preview")
make_AzureR_dir()

Просмотреть файл

@ -242,4 +242,4 @@ format_tenant <- function(tenant)
if(tenant == "common")
"default tenant"
else paste0("tenant '", tenant, "'")
}
}

Просмотреть файл

@ -22,6 +22,12 @@
#' - `get_lock(name`): Returns a management lock object.
#' - `delete_lock(name)`: Deletes a management lock object.
#' - `list_locks()`: List all locks that apply to this resource group. Note this includes locks created at the subscription level, and for any resources within the resource group.
#' - `add_role_assignment(name, ...)`: Adds a new role assignment. See 'Role-based access control' below.
#' - `get_role_assignment(id)`: Retrieves an existing role assignment.
#' - `remove_role_assignment(id)`: Removes an existing role assignment.
#' - `list_role_assignments()`: Lists role assignments.
#' - `get_role_definition(id)`: Retrieves an existing role definition.
#' - `list_role_definitions()` Lists role definitions.
#'
#' @section Initialization:
#' Initializing a new object of this class can either retrieve an existing resource group, or create a new resource group on the host. Generally, the easiest way to create a resource group object is via the `get_resource_group`, `create_resource_group` or `list_resource_groups` methods of the [az_subscription] class, which handle this automatically.
@ -53,12 +59,17 @@
#'
#' To create/deploy a new resource, specify any extra parameters that the provider needs as named arguments to `create_resource()`. Like `deploy_template()`, `create_resource()` also takes an optional `wait` argument that specifies whether to wait until resource creation is complete before returning.
#'
#' @section Role-based access control:
#' AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels. See [rbac] for more information.
#'
#' @seealso
#' [az_subscription], [az_template], [az_resource],
#' [Azure resource group overview](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview#resource-groups),
#' [Resources API reference](https://docs.microsoft.com/en-us/rest/api/resources/resources),
#' [Template API reference](https://docs.microsoft.com/en-us/rest/api/resources/deployments)
#'
#' For role-based access control methods, see [rbac]
#'
#' @examples
#' \dontrun{
#'

Просмотреть файл

@ -17,6 +17,12 @@
#' - `get_lock(name`): Returns a management lock object.
#' - `delete_lock(name)`: Deletes a management lock object.
#' - `list_locks()`: List all locks that apply to this resource. Note this includes locks created at the subscription or resource group level.
#' - `add_role_assignment(name, ...)`: Adds a new role assignment. See 'Role-based access control' below.
#' - `get_role_assignment(id)`: Retrieves an existing role assignment.
#' - `remove_role_assignment(id)`: Removes an existing role assignment.
#' - `list_role_assignments()`: Lists role assignments.
#' - `get_role_definition(id)`: Retrieves an existing role definition.
#' - `list_role_definitions()` Lists role definitions.
#'
#' @section Initialization:
#' There are multiple ways to initialize a new resource object. The `new()` method can retrieve an existing resource, deploy/create a new resource, or create an empty/null object (without communicating with the host), based on the arguments you supply.
@ -48,10 +54,15 @@
#'
#' Consult the Azure documentation for your resource to find out what operations are supported.
#'
#' @section Role-based access control:
#' AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels. See [rbac] for more information.
#'
#' @seealso
#' [az_resource_group], [call_azure_rm], [call_azure_url],
#' [Resources API reference](https://docs.microsoft.com/en-us/rest/api/resources/resources)
#'
#' For role-based access control methods, see [rbac]
#'
#' @examples
#' \dontrun{
#'

Просмотреть файл

@ -26,7 +26,8 @@
#' - `token`: Optionally, an OAuth 2.0 token, of class [AzureToken]. This allows you to reuse the authentication details for an existing session. If supplied, all other arguments will be ignored.
#'
#' @seealso
#' [create_azure_login], [get_azure_token], [AzureToken],
#' [create_azure_login], [get_azure_login]
#'
#' [Azure Resource Manager overview](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview),
#' [REST API reference](https://docs.microsoft.com/en-us/rest/api/resources/)
#'

138
R/az_role.R Normal file
Просмотреть файл

@ -0,0 +1,138 @@
#' Azure role definition class
#'
#' @docType class
#' @section Fields:
#' - `id`: The full resource ID for this role definition.
#' - `type`: The resource type for a role definition. Always `Microsoft.Authorization/roleDefinitions`.
#' - `name`: A GUID that identifies this role definition.
#' - `properties`: Properties for the role definition.
#'
#' @section Methods:
#' This class has no methods.
#'
#' @section Initialization:
#' The recommended way to create new instances of this class is via the [get_role_definition] method for subscription, resource group and resource objects.
#'
#' Technically role assignments and role definitions are Azure _resources_, and could be implemented as subclasses of `az_resource`. AzureRMR treats them as distinct, due to limited RBAC functionality currently supported. In particular, role definitions are read-only: you can retrieve a definition, but not modify it, nor create new definitions.
#'
#' @seealso
#' [get_role_definition], [get_role_assignment], [az_role_assignment]
#'
#' [Overview of role-based access control](https://docs.microsoft.com/en-us/azure/role-based-access-control/overview)
#'
#' @format An R6 object of class `az_role_definition`.
#' @export
az_role_definition <- R6::R6Class("az_role_definition",
public=list(
id=NULL,
name=NULL,
type=NULL,
properties=NULL,
initialize=function(parameters)
{
self$id <- parameters$id
self$name <- parameters$name
self$type <- parameters$type
self$properties <- parameters$properties
},
print=function(...)
{
cat("<Azure role definition>\n")
cat(" role:", self$properties$roleName, "\n")
cat(" description:", self$properties$description, "\n")
cat(" role definition ID:", self$name, "\n")
invisible(self)
}
))
#' Azure role assignment class
#'
#' @docType class
#' @section Fields:
#' - `id`: The full resource ID for this role assignment.
#' - `type`: The resource type for a role assignment. Always `Microsoft.Authorization/roleAssignments`.
#' - `name`: A GUID that identifies this role assignment.
#' - `role_name`: The role definition name (in text), eg "Contributor".
#' - `properties`: Properties for the role definition.
#' - `token`: An OAuth token, obtained via [get_azure_token].
#'
#' @section Methods:
#' - `remove(confirm=TRUE)`: Removes this role assignment.
#'
#' @section Initialization:
#' The recommended way to create new instances of this class is via the [add_role_assignment] and [get_role_assignment] methods for subscription, resource group and resource objects.
#'
#' Technically role assignments and role definitions are Azure _resources_, and could be implemented as subclasses of `az_resource`. AzureRMR treats them as distinct, due to limited RBAC functionality currently supported.
#'
#' @seealso
#' [add_role_assignment], [get_role_assignment], [get_role_definition], [az_role_definition]
#'
#' [Overview of role-based access control](https://docs.microsoft.com/en-us/azure/role-based-access-control/overview)
#'
#' @format An R6 object of class `az_role_assignment`.
#' @export
az_role_assignment <- R6::R6Class("az_role_assignment",
public=list(
# text name of role definition
role_name=NULL,
id=NULL,
name=NULL,
type=NULL,
properties=NULL,
token=NULL,
initialize=function(token, parameters, role_name=NULL, api_func=NULL)
{
self$token <- token
self$id <- parameters$id
self$name <- parameters$name
self$type <- parameters$type
self$properties <- parameters$properties
self$role_name <- role_name
private$api_func <- api_func
},
remove=function(confirm=TRUE)
{
if(confirm && interactive())
{
yn <- readline(paste0("Do you really want to delete role assignment '", self$name, "'? (y/N) "))
if(tolower(substr(yn, 1, 1)) != "y")
return(invisible(NULL))
}
op <- file.path("providers/Microsoft.Authorization/roleAssignments", self$name)
res <- private$api_func(op, api_version=getOption("azure_roleasn_api_version"), http_verb="DELETE")
if(attr(res, "status") == 204)
warning("Role assignment not found or could not be deleted")
invisible(NULL)
},
print=function(...)
{
cat("<Azure role assignment>\n")
cat(" principal:", self$properties$principalId, "\n")
if(!is_empty(self$role_name))
cat(" role:", self$role_name, "\n")
else cat(" role: <unknown>\n")
cat(" role definition ID:", basename(self$properties$roleDefinitionId), "\n")
cat(" role assignment ID:", self$name, "\n")
invisible(self)
}
),
private=list(
api_func=NULL
))

Просмотреть файл

@ -14,18 +14,29 @@
#' - `resource_group_exists(name)`: Check if a resource group exists.
#' - `list_resources()`: List all resources deployed under this subscription.
#' - `list_locations()`: List locations available.
#' - `get_provider_api_version(provider, type)`: Get the current API version for the given resource provider and type. If no resource type is supplied, returns a vector of API versions, one for each resource type for the given provider. If neither provider nor type is supplied, returns the API versions for all resources and providers.
#' - `create_lock(name, level)`: Create a management lock on this subscription (which will propagate to all resources within it). The `level` argument can be either "cannotdelete" or "readonly". Note if you logged in via a custom service principal, it must have "Owner" or "User Access Administrator" access to manage locks.
#' - `get_lock(name`): Returns a management lock object.
#' - `delete_lock(name)`: Deletes a management lock object.
#' - `list_locks()`: List all locks that exist in this subscription.
#' - `get_provider_api_version(provider, type)`: Get the current API version for the given resource provider and type. If no resource type is supplied, returns a vector of API versions, one for each resource type for the given provider. If neither provider nor type is supplied, returns the API versions for all resources and providers.
#' - `add_role_assignment(name, ...)`: Adds a new role assignment. See 'Role-based access control' below.
#' - `get_role_assignment(id)`: Retrieves an existing role assignment.
#' - `remove_role_assignment(id)`: Removes an existing role assignment.
#' - `list_role_assignments()`: Lists role assignments.
#' - `get_role_definition(id)`: Retrieves an existing role definition.
#' - `list_role_definitions()` Lists role definitions.
#'
#' @section Details:
#' Generally, the easiest way to create a subscription object is via the `get_subscription` or `list_subscriptions` methods of the [az_rm] class. To create a subscription object in isolation, call the `new()` method and supply an Oauth 2.0 token of class [AzureToken], along with the ID of the subscription.
#'
#' @section Role-based access control:
#' AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels. See [rbac] for more information.
#'
#' @seealso
#' [Azure Resource Manager overview](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview)
#'
#' For role-based access control methods, see [rbac]
#'
#' @examples
#' \dontrun{
#'
@ -84,7 +95,7 @@ public=list(
list_locations=function()
{
cont <- call_azure_rm(self$token, self$id, "locations")
cont <- private$sub_op("locations")
locs <- do.call(rbind, lapply(cont$value, data.frame, stringsAsFactors=FALSE))
within(locs,
{
@ -99,7 +110,7 @@ public=list(
{
if(is_empty(provider))
{
apis <- named_list(call_azure_rm(self$token, self$id, "providers")$value, "namespace")
apis <- named_list(private$sub_op("providers")$value, "namespace")
lapply(apis, function(api)
{
api <- named_list(api$resourceTypes, "resourceType")
@ -110,7 +121,7 @@ public=list(
else
{
op <- construct_path("providers", provider)
apis <- named_list(call_azure_rm(self$token, self$id, op)$resourceTypes, "resourceType")
apis <- named_list(private$sub_op(op)$resourceTypes, "resourceType")
if(!is_empty(type))
{
# case-insensitive matching
@ -131,7 +142,7 @@ public=list(
list_resource_groups=function()
{
cont <- call_azure_rm(self$token, self$id, "resourcegroups")
cont <- private$sub_op("resourcegroups")
lst <- lapply(cont$value, function(parms) az_resource_group$new(self$token, self$id, parms=parms))
# keep going until paging is complete
while(!is_empty(cont$nextLink))
@ -156,14 +167,14 @@ public=list(
resource_group_exists=function(name)
{
res <- call_azure_rm(self$token, self$id, construct_path("resourceGroups", name),
res <- private$sub_op(construct_path("resourceGroups", name),
http_verb="HEAD", http_status_handler="pass")
httr::status_code(res) < 300
},
list_resources=function()
{
cont <- call_azure_rm(self$token, self$id, "resources")
cont <- private$sub_op("resources")
lst <- lapply(cont$value, function(parms) az_resource$new(self$token, self$id, deployed_properties=parms))
# keep going until paging is complete
while(!is_empty(cont$nextLink))
@ -185,7 +196,7 @@ public=list(
if(notes != "")
body$notes <- notes
res <- call_azure_rm(self$token, self$id, op, body=body, encode="json", http_verb="PUT", api_version=api)
res <- private$sub_op(op, body=body, encode="json", http_verb="PUT", api_version=api)
az_resource$new(self$token, self$id, deployed_properties=res, api_version=api)
},
@ -193,7 +204,7 @@ public=list(
{
api <- getOption("azure_api_mgmt_version")
op <- file.path("providers/Microsoft.Authorization/locks", name)
res <- call_azure_rm(self$token, self$id, op, api_version=api)
res <- private$sub_op(op, api_version=api)
az_resource$new(self$token, self$id, deployed_properties=res, api_version=api)
},
@ -201,7 +212,7 @@ public=list(
{
api <- getOption("azure_api_mgmt_version")
op <- file.path("providers/Microsoft.Authorization/locks", name)
call_azure_rm(self$token, self$id, op, http_verb="DELETE", api_version=api)
private$sub_op(op, http_verb="DELETE", api_version=api)
invisible(NULL)
},
@ -209,7 +220,7 @@ public=list(
{
api <- getOption("azure_api_mgmt_version")
op <- "providers/Microsoft.Authorization/locks"
cont <- call_azure_rm(self$token, self$id, op, api_version=api)
cont <- private$sub_op(op, api_version=api)
lst <- lapply(cont$value, function(parms)
az_resource$new(self$token, self$subscription, deployed_properties=parms, api_version=api))
@ -231,4 +242,12 @@ public=list(
cat(format_public_methods(self))
invisible(self)
}
),
private=list(
sub_op=function(op="", ...)
{
call_azure_rm(self$token, self$id, op, ...)
}
))

Просмотреть файл

@ -1,7 +1,7 @@
#' Call the Azure Resource Manager REST API
#'
#' @param token An Azure OAuth token, of class [AzureToken].
#' @param subscription A subscription ID.
#' @param subscription For `call_azure_rm`, a subscription ID.
#' @param operation The operation to perform, which will form part of the URL path.
#' @param options A named list giving the URL query parameters.
#' @param api_version The API version to use, which will form part of the URL sent to the host.
@ -12,7 +12,7 @@
#' @param ... Other arguments passed to lower-level code, ultimately to the appropriate functions in httr.
#'
#' @details
#' These functions form the low-level interface between AzureRMR and Resource Manager. `call_azure_rm` builds a URL from its arguments and passes it to `call_azure_url`. Authentication is handled automatically.
#' These functions form the low-level interface between R and Azure. `call_azure_rm` is for calling the Resource Manager API, and `call_azure_graph` is for calling the Azure Active Directory Graph API. They build a URL from their arguments and pass it to `call_azure_url`. Authentication is handled automatically.
#'
#' @return
#' If `http_status_handler` is one of `"stop"`, `"warn"` or `"message"`, the status code of the response is checked. If an error is not thrown, the parsed content of the response is returned with the status code attached as the "status" attribute.
@ -78,10 +78,10 @@ process_response <- function(response, handler)
{
if(handler != "pass")
{
handler <- get(paste0(handler, "_for_status"), getNamespace("httr"))
handler(response, paste0("complete Resource Manager operation. Message:\n",
sub("\\.$", "", arm_error_message(response))))
cont <- httr::content(response)
handler <- get(paste0(handler, "_for_status"), getNamespace("httr"))
handler(response, paste0("complete operation. Message:\n",
sub("\\.$", "", error_message(cont))))
if(is.null(cont))
cont <- list()
attr(cont, "status") <- httr::status_code(response)
@ -91,18 +91,21 @@ process_response <- function(response, handler)
}
# provide complete error messages from Resource Manager
arm_error_message <- function(response)
# provide complete error messages from Resource Manager/AAD Graph/etc
error_message <- function(cont)
{
cont <- httr::content(response)
# kiboze through possible message locations
msg <- if(is.character(cont))
cont
else if(is.list(cont) && is.character(cont$message))
cont$message
else if(is.list(cont) && is.list(cont$error) && is.character(cont$error$message))
cont$error$message
else if(is.list(cont))
{
if(is.character(cont$message))
cont$message
else if(is.list(cont$error) && is.character(cont$error$message))
cont$error$message
else if(is.list(cont$odata.error)) # Graph OData
cont$odata.error$message$value
}
else ""
paste0(strwrap(msg), collapse="\n")

15
R/is.R
Просмотреть файл

@ -45,3 +45,18 @@ is_template <- function(object)
R6::is.R6(object) && inherits(object, "az_template")
}
#' @rdname is
#' @export
is_role_definition <- function(object)
{
R6::is.R6(object) && inherits(object, "az_role_definition")
}
#' @rdname is
#' @export
is_role_assignment <- function(object)
{
R6::is.R6(object) && inherits(object, "az_role_assignment")
}

310
R/rbac.R Normal file
Просмотреть файл

@ -0,0 +1,310 @@
#' Role-based access control (RBAC)
#'
#' Basic methods for RBAC: manage role assignments and retrieve role definitions. These are methods for the `az_subscription`, `az_resource_group` and `az_resource` classes.
#'
#' @section Usage:
#' ```
#' add_role_assignment(principal, role, scope = NULL)
#'
#' get_role_assignment(id)
#'
#' remove_role_assignment(id, confirm = TRUE)
#'
#' list_role_assignments(filter = "atScope()", as_data_frame = TRUE)
#'
#' get_role_definition(id)
#'
#' list_role_definitions(filter=NULL, as_data_frame = TRUE)
#' ```
#' @section Arguments:
#' - `principal`: For `add_role_assignment`, the principal for which to assign a role. This can be a GUID, or an object of class `az_app` or `az_storage_principal` (from the AzureGraph package).
#' - `role`: For `add_role_assignment`, the role to assign the principal. This can be a GUID, a string giving the role name (eg "Contributor"), or an object of class `[az_role_definition]`.
#' - `scope`: For `add_role_assignment`, an optional scope for the assignment.
#' - `id`: A role ID. For `get_role_assignment` and `remove_role_assignment`, this is a role assignment GUID. For `get_role_definition`, this can be a role definition GUID or a role name.
#' - `confirm`: For `remove_role_assignment`, whether to ask for confirmation before removing the role assignment.
#' - `filter`: For `list_role_assignments` and `list_role_definitions`, an optional filter condition to limit the returned roles.
#' - `as_data_frame`: For `list_role_assignments` and `list_role_definitions`, whether to return a data frame or a list of objects. See 'Value' below.
#'
#' @section Details:
#' AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels.
#'
#' @section Value:
#' The `add_role_assignment` and `get_role_assignment` methods return an object of class `az_role_assignment`. This is a simple R6 class, with one method: `remove` to remove the assignment.
#'
#' The `list_role_assignments` method returns a list of `az_role_assignment` objects if the `as_data_frame` argument is FALSE. If this is TRUE, it instead returns a data frame containing the most broadly useful fields for each assigned role: the role assignment ID, the principal, and the role name.
#'
#' The `get_role_definition` method returns an object of class `az_role_definition`. This is a plain-old-data R6 class (no methods), which can be used as input for creating role assignments (see the examples below).
#'
#' The `list_role_definitions` method returns a list of `az_role_definition` if the `as_data_frame` argument is FALSE. If this is TRUE, it instead returns a data frame containing the most broadly useful fields for each role definition: the definition ID and role name.
#'
#' @seealso
#' [az_rm], [az_role_definition], [az_role_assignment]
#'
#' [Overview of role-based access control](https://docs.microsoft.com/en-us/azure/role-based-access-control/overview)
#'
#' @examples
#' \dontrun{
#'
#' az <- get_azure_login("myaadtenant")
#' sub <- az$get_subscription("subscription_id")
#' rg <- sub$get_resource_group("rgname")
#' res <- rg$get_resource(type="provider_type", name="resname")
#'
#' sub$list_role_definitions()
#' sub$list_role_assignments()
#' sub$get_role_definition("Contributor")
#'
#' # get an app using the AzureGraph package
#' app <- az_graph$new("myaadtenant")$get_app("app_id")
#'
#' # subscription level
#' asn1 <- sub$add_role_assignment(app, "Reader")
#'
#' # resource group level
#' asn2 <- rg$add_role_assignment(app, "Contributor")
#'
#' # resource level
#' asn3 <- res$add_role_assignment(app, "Owner")
#'
#' res$remove_role_assignment(asn3$id)
#' rg$remove_role_assignment(asn2$id)
#' sub$remove_role_assignment(asn1$id)
#'
#' }
#'
#' @aliases rbac add_role_assignment get_role_assignment remove_role_assignment list_role_assignments
#' get_role_definition list_role_definitions
#' @rdname rbac
#' @name rbac
NULL
## subscription methods
az_subscription$set("public", "add_role_assignment", overwrite=TRUE,
function(principal, role, scope=NULL)
{
if(!is_role_definition(role))
role <- self$get_role_definition(role)
add_role_assignment(principal, role, scope, private$sub_op)
})
az_subscription$set("public", "get_role_assignment", overwrite=TRUE,
function(id)
{
get_role_assignment(id, self$list_role_definitions(), private$sub_op)
})
az_subscription$set("public", "remove_role_assignment", overwrite=TRUE,
function(id, confirm=TRUE)
{
remove_role_assignment(id, confirm, private$sub_op)
})
az_subscription$set("public", "list_role_assignments", overwrite=TRUE,
function(filter="atScope()", as_data_frame=TRUE)
{
list_role_assignments(filter, as_data_frame, self$list_role_definitions(), private$sub_op)
})
az_subscription$set("public", "get_role_definition", overwrite=TRUE,
function(id)
{
get_role_definition(id, private$sub_op)
})
az_subscription$set("public", "list_role_definitions", overwrite=TRUE,
function(filter=NULL, as_data_frame=TRUE)
{
list_role_definitions(filter, as_data_frame, private$sub_op)
})
## resource group methods
az_resource_group$set("public", "add_role_assignment", overwrite=TRUE,
function(principal, role, scope=NULL)
{
if(!is_role_definition(role))
role <- self$get_role_definition(role)
add_role_assignment(principal, role, scope, private$rg_op)
})
az_resource_group$set("public", "get_role_assignment", overwrite=TRUE,
function(id)
{
get_role_assignment(id, self$list_role_definitions(), private$rg_op)
})
az_resource_group$set("public", "remove_role_assignment", overwrite=TRUE,
function(id, confirm=TRUE)
{
remove_role_assignment(id, confirm, private$rg_op)
})
az_resource_group$set("public", "list_role_assignments", overwrite=TRUE,
function(filter="atScope()", as_data_frame=TRUE)
{
list_role_assignments(filter, as_data_frame, self$list_role_definitions(), private$rg_op)
})
az_resource_group$set("public", "get_role_definition", overwrite=TRUE,
function(id)
{
get_role_definition(id, private$rg_op)
})
az_resource_group$set("public", "list_role_definitions", overwrite=TRUE,
function(filter=NULL, as_data_frame=TRUE)
{
list_role_definitions(filter, as_data_frame, private$rg_op)
})
## resource methods
az_resource$set("public", "add_role_assignment", overwrite=TRUE,
function(principal, role, scope=NULL)
{
if(!is_role_definition(role))
role <- self$get_role_definition(role)
add_role_assignment(principal, role, scope, private$res_op)
})
az_resource$set("public", "get_role_assignment", overwrite=TRUE,
function(id)
{
get_role_assignment(id, self$list_role_definitions(), private$res_op)
})
az_resource$set("public", "remove_role_assignment", overwrite=TRUE,
function(id, confirm=TRUE)
{
remove_role_assignment(id, confirm, private$res_op)
})
az_resource$set("public", "list_role_assignments", overwrite=TRUE,
function(filter="atScope()", as_data_frame=TRUE)
{
list_role_assignments(filter, as_data_frame, self$list_role_definitions(), private$res_op)
})
az_resource$set("public", "get_role_definition", overwrite=TRUE,
function(id)
{
get_role_definition(id, private$res_op)
})
az_resource$set("public", "list_role_definitions", overwrite=TRUE,
function(filter=NULL, as_data_frame=TRUE)
{
list_role_definitions(filter, as_data_frame, private$res_op)
})
## implementations
add_role_assignment <- function(principal, role, scope, api_func)
{
# obtain object ID from a service principal or registered app
if(inherits(principal, "az_service_principal"))
principal <- principal$properties$objectId
else if(inherits(principal, "az_app"))
principal <- principal$get_service_principal()$properties$objectId
token <- environment(api_func)$self$token
op <- file.path("providers/Microsoft.Authorization/roleAssignments", uuid::UUIDgenerate())
body <- list(
properties=list(
roleDefinitionId=role$id,
principalId=principal
)
)
if(!is.null(scope))
body$properties$scope <- scope
res <- api_func(op, body=body, encode="json",
api_version=getOption("azure_roleasn_api_version"), http_verb="PUT")
az_role_assignment$new(token, res, role$properties$roleName, api_func)
}
get_role_assignment <- function(id, defs, api_func)
{
token <- environment(api_func)$self$token
op <- file.path("providers/Microsoft.Authorization/roleAssignments", id)
res <- api_func(op, api_version=getOption("azure_roleasn_api_version"))
role_name <- defs$name[defs$definition_id == basename(res$properties$roleDefinitionId)]
az_role_assignment$new(token, res, role_name, api_func)
}
remove_role_assignment <- function(id, confirm, api_func)
{
token <- environment(api_func)$self$token
# pass minimal list of parameters to init, rather than making useless API calls
res <- list(name=basename(id))
az_role_assignment$new(token, res, api_func=api_func)$remove(confirm=confirm)
}
list_role_assignments <- function(filter, as_data_frame, defs, api_func)
{
token <- environment(api_func)$self$token
op <- "providers/Microsoft.Authorization/roleAssignments"
lst <- api_func(op, options=list(`$filter`=filter), api_version=getOption("azure_roleasn_api_version"))
if(as_data_frame)
{
lst <- lapply(lst$value, function(res)
{
role_name <- defs$name[defs$definition_id == basename(res$properties$roleDefinitionId)]
data.frame(assignment_id=res$name, principal=res$properties$principalId, role=role_name,
stringsAsFactors=FALSE)
})
do.call(rbind, lst)
}
else lapply(lst$value, function(res)
{
role_name <- defs$name[defs$definition_id == basename(res$properties$roleDefinitionId)]
az_role_assignment$new(token, res, role_name, api_func)
})
}
get_role_definition <- function(id, api_func)
{
# if text rolename supplied, use it to filter the list of roles
if(!is_guid(id))
{
op <- "providers/Microsoft.Authorization/roleDefinitions"
filter <- sprintf("roleName eq '%s'", id)
lst <- api_func(op, options=list(`$filter`=filter), api_version=getOption("azure_roledef_api_version"))
if(is_empty(lst$value))
stop("Role definition not found", call.=FALSE)
return(az_role_definition$new(lst$value[[1]]))
}
op <- file.path("providers/Microsoft.Authorization/roleDefinitions", id)
res <- api_func(op, api_version=getOption("azure_roledef_api_version"))
az_role_definition$new(res)
}
list_role_definitions <- function(filter, as_data_frame, api_func)
{
op <- "providers/Microsoft.Authorization/roleDefinitions"
lst <- api_func(op, options=list(`$filter`=filter), api_version=getOption("azure_roledef_api_version"))
if(as_data_frame)
{
lst <- lapply(lst$value, function(res)
data.frame(definition_id=res$name, name=res$properties$roleName, stringsAsFactors=FALSE))
do.call(rbind, lst)
}
else
{
lst <- lapply(lst$value, function(res)
az_role_definition$new(res))
names(lst) <- sapply(lst, function(res) res$properties$roleName)
lst
}
}

Просмотреть файл

@ -27,6 +27,12 @@ Class representing a generic Azure resource.
\item \code{get_lock(name}): Returns a management lock object.
\item \code{delete_lock(name)}: Deletes a management lock object.
\item \code{list_locks()}: List all locks that apply to this resource. Note this includes locks created at the subscription or resource group level.
\item \code{add_role_assignment(name, ...)}: Adds a new role assignment. See 'Role-based access control' below.
\item \code{get_role_assignment(id)}: Retrieves an existing role assignment.
\item \code{remove_role_assignment(id)}: Removes an existing role assignment.
\item \code{list_role_assignments()}: Lists role assignments.
\item \code{get_role_definition(id)}: Retrieves an existing role definition.
\item \code{list_role_definitions()} Lists role definitions.
}
}
@ -70,6 +76,11 @@ The \code{do_operation()} method allows you to carry out arbitrary operations on
Consult the Azure documentation for your resource to find out what operations are supported.
}
\section{Role-based access control}{
AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels. See \link{rbac} for more information.
}
\examples{
\dontrun{
@ -119,5 +130,7 @@ stor$delete()
\seealso{
\link{az_resource_group}, \link{call_azure_rm}, \link{call_azure_url},
\href{https://docs.microsoft.com/en-us/rest/api/resources/resources}{Resources API reference}
For role-based access control methods, see \link{rbac}
}
\keyword{datasets}

Просмотреть файл

@ -32,6 +32,12 @@ Class representing an Azure resource group.
\item \code{get_lock(name}): Returns a management lock object.
\item \code{delete_lock(name)}: Deletes a management lock object.
\item \code{list_locks()}: List all locks that apply to this resource group. Note this includes locks created at the subscription level, and for any resources within the resource group.
\item \code{add_role_assignment(name, ...)}: Adds a new role assignment. See 'Role-based access control' below.
\item \code{get_role_assignment(id)}: Retrieves an existing role assignment.
\item \code{remove_role_assignment(id)}: Removes an existing role assignment.
\item \code{list_role_assignments()}: Lists role assignments.
\item \code{get_role_definition(id)}: Retrieves an existing role definition.
\item \code{list_role_definitions()} Lists role definitions.
}
}
@ -77,6 +83,11 @@ Providing the \code{id} argument will fill in the values for all the other argum
To create/deploy a new resource, specify any extra parameters that the provider needs as named arguments to \code{create_resource()}. Like \code{deploy_template()}, \code{create_resource()} also takes an optional \code{wait} argument that specifies whether to wait until resource creation is complete before returning.
}
\section{Role-based access control}{
AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels. See \link{rbac} for more information.
}
\examples{
\dontrun{
@ -123,5 +134,7 @@ rg$delete()
\href{https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview#resource-groups}{Azure resource group overview},
\href{https://docs.microsoft.com/en-us/rest/api/resources/resources}{Resources API reference},
\href{https://docs.microsoft.com/en-us/rest/api/resources/deployments}{Template API reference}
For role-based access control methods, see \link{rbac}
}
\keyword{datasets}

Просмотреть файл

@ -1,5 +1,5 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/az_auth.R
% Please edit documentation in R/az_rm.R
\docType{class}
\name{az_rm}
\alias{az_rm}
@ -60,7 +60,8 @@ az$get_subscription("subscription_id")
}
}
\seealso{
\link{create_azure_login}, \link{get_azure_token}, \link{AzureToken},
\link{create_azure_login}, \link{get_azure_login}
\href{https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview}{Azure Resource Manager overview},
\href{https://docs.microsoft.com/en-us/rest/api/resources/}{REST API reference}
}

45
man/az_role_assignment.Rd Normal file
Просмотреть файл

@ -0,0 +1,45 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/az_role.R
\docType{class}
\name{az_role_assignment}
\alias{az_role_assignment}
\title{Azure role assignment class}
\format{An R6 object of class \code{az_role_assignment}.}
\usage{
az_role_assignment
}
\description{
Azure role assignment class
}
\section{Fields}{
\itemize{
\item \code{id}: The full resource ID for this role assignment.
\item \code{type}: The resource type for a role assignment. Always \code{Microsoft.Authorization/roleAssignments}.
\item \code{name}: A GUID that identifies this role assignment.
\item \code{role_name}: The role definition name (in text), eg "Contributor".
\item \code{properties}: Properties for the role definition.
\item \code{token}: An OAuth token, obtained via \link{get_azure_token}.
}
}
\section{Methods}{
\itemize{
\item \code{remove(confirm=TRUE)}: Removes this role assignment.
}
}
\section{Initialization}{
The recommended way to create new instances of this class is via the \link{add_role_assignment} and \link{get_role_assignment} methods for subscription, resource group and resource objects.
Technically role assignments and role definitions are Azure \emph{resources}, and could be implemented as subclasses of \code{az_resource}. AzureRMR treats them as distinct, due to limited RBAC functionality currently supported.
}
\seealso{
\link{add_role_assignment}, \link{get_role_assignment}, \link{get_role_definition}, \link{az_role_definition}
\href{https://docs.microsoft.com/en-us/azure/role-based-access-control/overview}{Overview of role-based access control}
}
\keyword{datasets}

41
man/az_role_definition.Rd Normal file
Просмотреть файл

@ -0,0 +1,41 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/az_role.R
\docType{class}
\name{az_role_definition}
\alias{az_role_definition}
\title{Azure role definition class}
\format{An R6 object of class \code{az_role_definition}.}
\usage{
az_role_definition
}
\description{
Azure role definition class
}
\section{Fields}{
\itemize{
\item \code{id}: The full resource ID for this role definition.
\item \code{type}: The resource type for a role definition. Always \code{Microsoft.Authorization/roleDefinitions}.
\item \code{name}: A GUID that identifies this role definition.
\item \code{properties}: Properties for the role definition.
}
}
\section{Methods}{
This class has no methods.
}
\section{Initialization}{
The recommended way to create new instances of this class is via the \link{get_role_definition} method for subscription, resource group and resource objects.
Technically role assignments and role definitions are Azure \emph{resources}, and could be implemented as subclasses of \code{az_resource}. AzureRMR treats them as distinct, due to limited RBAC functionality currently supported. In particular, role definitions are read-only: you can retrieve a definition, but not modify it, nor create new definitions.
}
\seealso{
\link{get_role_definition}, \link{get_role_assignment}, \link{az_role_assignment}
\href{https://docs.microsoft.com/en-us/azure/role-based-access-control/overview}{Overview of role-based access control}
}
\keyword{datasets}

Просмотреть файл

@ -22,11 +22,17 @@ Class representing an Azure subscription.
\item \code{resource_group_exists(name)}: Check if a resource group exists.
\item \code{list_resources()}: List all resources deployed under this subscription.
\item \code{list_locations()}: List locations available.
\item \code{get_provider_api_version(provider, type)}: Get the current API version for the given resource provider and type. If no resource type is supplied, returns a vector of API versions, one for each resource type for the given provider. If neither provider nor type is supplied, returns the API versions for all resources and providers.
\item \code{create_lock(name, level)}: Create a management lock on this subscription (which will propagate to all resources within it). The \code{level} argument can be either "cannotdelete" or "readonly". Note if you logged in via a custom service principal, it must have "Owner" or "User Access Administrator" access to manage locks.
\item \code{get_lock(name}): Returns a management lock object.
\item \code{delete_lock(name)}: Deletes a management lock object.
\item \code{list_locks()}: List all locks that exist in this subscription.
\item \code{get_provider_api_version(provider, type)}: Get the current API version for the given resource provider and type. If no resource type is supplied, returns a vector of API versions, one for each resource type for the given provider. If neither provider nor type is supplied, returns the API versions for all resources and providers.
\item \code{add_role_assignment(name, ...)}: Adds a new role assignment. See 'Role-based access control' below.
\item \code{get_role_assignment(id)}: Retrieves an existing role assignment.
\item \code{remove_role_assignment(id)}: Removes an existing role assignment.
\item \code{list_role_assignments()}: Lists role assignments.
\item \code{get_role_definition(id)}: Retrieves an existing role definition.
\item \code{list_role_definitions()} Lists role definitions.
}
}
@ -35,6 +41,11 @@ Class representing an Azure subscription.
Generally, the easiest way to create a subscription object is via the \code{get_subscription} or \code{list_subscriptions} methods of the \link{az_rm} class. To create a subscription object in isolation, call the \code{new()} method and supply an Oauth 2.0 token of class \link{AzureToken}, along with the ID of the subscription.
}
\section{Role-based access control}{
AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels. See \link{rbac} for more information.
}
\examples{
\dontrun{
@ -64,5 +75,7 @@ sub$get_provider_api_version("Microsoft.Storage", "storageAccounts")
}
\seealso{
\href{https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview}{Azure Resource Manager overview}
For role-based access control methods, see \link{rbac}
}
\keyword{datasets}

Просмотреть файл

@ -15,7 +15,7 @@ call_azure_url(token, url, ..., http_verb = c("GET", "DELETE", "PUT",
\arguments{
\item{token}{An Azure OAuth token, of class \link{AzureToken}.}
\item{subscription}{A subscription ID.}
\item{subscription}{For \code{call_azure_rm}, a subscription ID.}
\item{operation}{The operation to perform, which will form part of the URL path.}
@ -42,7 +42,7 @@ If \code{http_status_handler} is \code{"pass"}, the entire response is returned
Call the Azure Resource Manager REST API
}
\details{
These functions form the low-level interface between AzureRMR and Resource Manager. \code{call_azure_rm} builds a URL from its arguments and passes it to \code{call_azure_url}. Authentication is handled automatically.
These functions form the low-level interface between R and Azure. \code{call_azure_rm} is for calling the Resource Manager API, and \code{call_azure_graph} is for calling the Azure Active Directory Graph API. They build a URL from their arguments and pass it to \code{call_azure_url}. Authentication is handled automatically.
}
\seealso{
\link[httr:GET]{httr::GET}, \link[httr:PUT]{httr::PUT}, \link[httr:POST]{httr::POST}, \link[httr:DELETE]{httr::DELETE}, \link[httr:stop_for_status]{httr::stop_for_status}, \link[httr:content]{httr::content}

Просмотреть файл

@ -6,6 +6,8 @@
\alias{is_resource_group}
\alias{is_resource}
\alias{is_template}
\alias{is_role_definition}
\alias{is_role_assignment}
\title{Informational functions}
\usage{
is_azure_login(object)
@ -17,6 +19,10 @@ is_resource_group(object)
is_resource(object)
is_template(object)
is_role_definition(object)
is_role_assignment(object)
}
\arguments{
\item{object}{An R object.}

94
man/rbac.Rd Normal file
Просмотреть файл

@ -0,0 +1,94 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/rbac.R
\name{rbac}
\alias{rbac}
\alias{add_role_assignment}
\alias{get_role_assignment}
\alias{remove_role_assignment}
\alias{list_role_assignments}
\alias{get_role_definition}
\alias{list_role_definitions}
\title{Role-based access control (RBAC)}
\description{
Basic methods for RBAC: manage role assignments and retrieve role definitions. These are methods for the \code{az_subscription}, \code{az_resource_group} and \code{az_resource} classes.
}
\section{Usage}{
\preformatted{add_role_assignment(principal, role, scope = NULL)
get_role_assignment(id)
remove_role_assignment(id, confirm = TRUE)
list_role_assignments(filter = "atScope()", as_data_frame = TRUE)
get_role_definition(id)
list_role_definitions(filter=NULL, as_data_frame = TRUE)
}
}
\section{Arguments}{
\itemize{
\item \code{principal}: For \code{add_role_assignment}, the principal for which to assign a role. This can be a GUID, or an object of class \code{az_app} or \code{az_storage_principal} (from the AzureGraph package).
\item \code{role}: For \code{add_role_assignment}, the role to assign the principal. This can be a GUID, a string giving the role name (eg "Contributor"), or an object of class \code{[az_role_definition]}.
\item \code{scope}: For \code{add_role_assignment}, an optional scope for the assignment.
\item \code{id}: A role ID. For \code{get_role_assignment} and \code{remove_role_assignment}, this is a role assignment GUID. For \code{get_role_definition}, this can be a role definition GUID or a role name.
\item \code{confirm}: For \code{remove_role_assignment}, whether to ask for confirmation before removing the role assignment.
\item \code{filter}: For \code{list_role_assignments} and \code{list_role_definitions}, an optional filter condition to limit the returned roles.
\item \code{as_data_frame}: For \code{list_role_assignments} and \code{list_role_definitions}, whether to return a data frame or a list of objects. See 'Value' below.
}
}
\section{Details}{
AzureRMR implements a subset of the full RBAC functionality within Azure Active Directory. You can retrieve role definitions and add and remove role assignments, at the subscription, resource group and resource levels.
}
\section{Value}{
The \code{add_role_assignment} and \code{get_role_assignment} methods return an object of class \code{az_role_assignment}. This is a simple R6 class, with one method: \code{remove} to remove the assignment.
The \code{list_role_assignments} method returns a list of \code{az_role_assignment} objects if the \code{as_data_frame} argument is FALSE. If this is TRUE, it instead returns a data frame containing the most broadly useful fields for each assigned role: the role assignment ID, the principal, and the role name.
The \code{get_role_definition} method returns an object of class \code{az_role_definition}. This is a plain-old-data R6 class (no methods), which can be used as input for creating role assignments (see the examples below).
The \code{list_role_definitions} method returns a list of \code{az_role_definition} if the \code{as_data_frame} argument is FALSE. If this is TRUE, it instead returns a data frame containing the most broadly useful fields for each role definition: the definition ID and role name.
}
\examples{
\dontrun{
az <- get_azure_login("myaadtenant")
sub <- az$get_subscription("subscription_id")
rg <- sub$get_resource_group("rgname")
res <- rg$get_resource(type="provider_type", name="resname")
sub$list_role_definitions()
sub$list_role_assignments()
sub$get_role_definition("Contributor")
# get an app using the AzureGraph package
app <- az_graph$new("myaadtenant")$get_app("app_id")
# subscription level
asn1 <- sub$add_role_assignment(app, "Reader")
# resource group level
asn2 <- rg$add_role_assignment(app, "Contributor")
# resource level
asn3 <- res$add_role_assignment(app, "Owner")
res$remove_role_assignment(asn3$id)
rg$remove_role_assignment(asn2$id)
sub$remove_role_assignment(asn1$id)
}
}
\seealso{
\link{az_rm}, \link{az_role_definition}, \link{az_role_assignment}
\href{https://docs.microsoft.com/en-us/azure/role-based-access-control/overview}{Overview of role-based access control}
}

Просмотреть файл

@ -9,7 +9,7 @@ if(tenant == "" || app == "" || password == "" || subscription == "")
skip("Authentication tests skipped: ARM credentials not set")
test_that("Authentication works",
test_that("ARM authentication works",
{
az <- az_rm$new(tenant=tenant, app=app, password=password)
expect_is(az, "az_rm")
@ -23,9 +23,11 @@ test_that("Authentication works",
expect_true(is_azure_token(az2$token))
})
test_that("Login interface works",
{
lst <- list_azure_logins()
expect_true(is.list(lst))
az3 <- create_azure_login(tenant=tenant, app=app, password=password)
expect_is(az3, "az_rm")

Просмотреть файл

@ -49,6 +49,7 @@ test_that("Template methods work",
expect_false(is_empty(rg$list_resources()))
tpl2$delete(confirm=FALSE, free_resources=TRUE)
Sys.sleep(2)
expect_true(is_empty(rg$list_resources()))
# leave out parameters arg, modify template to incorporate parameters

Просмотреть файл

@ -0,0 +1,98 @@
context("RBAC")
tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
app <- Sys.getenv("AZ_TEST_APP_ID")
password <- Sys.getenv("AZ_TEST_PASSWORD")
subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
newsvc_id <- Sys.getenv("AZ_TEST_SVC_PRINCIPAL_ID")
if(tenant == "" || app == "" || password == "" || subscription == "" || newsvc_id == "")
skip("RBAC method tests skipped: ARM credentials not set")
az <- az_rm$new(tenant, app, password)
sub <- az$get_subscription(subscription)
rgname <- paste(sample(letters, 20, replace=TRUE), collapse="")
test_that("Subscription RBAC works",
{
defs <- sub$list_role_definitions()
expect_is(defs, "data.frame")
defs_lst <- sub$list_role_definitions(as_data_frame=FALSE)
expect_is(defs_lst, "list")
expect_true(all(sapply(defs_lst, is_role_definition)))
asns <- sub$list_role_assignments()
expect_is(asns, "data.frame")
asns_lst <- sub$list_role_assignments(as_data_frame=FALSE)
expect_is(asns_lst, "list")
expect_true(all(sapply(asns_lst, is_role_assignment)))
asn <- sub$add_role_assignment(newsvc_id, "reader")
expect_true(is_role_assignment(asn))
newasns <- sub$list_role_assignments()
expect_true(newsvc_id %in% newasns$principal)
expect_silent(sub$remove_role_assignment(asn$name, confirm=FALSE))
})
test_that("Resource group RBAC works",
{
expect_false(sub$resource_group_exists(rgname))
rg <- sub$create_resource_group(rgname, location="westus")
defs <- rg$list_role_definitions()
expect_is(defs, "data.frame")
defs_lst <- rg$list_role_definitions(as_data_frame=FALSE)
expect_is(defs_lst, "list")
expect_true(all(sapply(defs_lst, is_role_definition)))
asns <- sub$list_role_assignments()
expect_is(asns, "data.frame")
asns_lst <- rg$list_role_assignments(as_data_frame=FALSE)
expect_is(asns_lst, "list")
expect_true(all(sapply(asns_lst, is_role_assignment)))
asn <- rg$add_role_assignment(newsvc_id, "contributor")
expect_true(is_role_assignment(asn))
expect_silent(rg$remove_role_assignment(asn$name, confirm=FALSE))
})
test_that("Resource RBAC works",
{
restype <- "Microsoft.Storage/storageAccounts"
resname <- paste(sample(letters, 20, replace=TRUE), collapse="")
rg <- sub$get_resource_group(rgname)
res <- rg$create_resource(type=restype, name=resname,
kind="Storage",
sku=list(name="Standard_LRS", tier="Standard"))
defs <- res$list_role_definitions()
expect_is(defs, "data.frame")
defs_lst <- res$list_role_definitions(as_data_frame=FALSE)
expect_is(defs_lst, "list")
expect_true(all(sapply(defs_lst, is_role_definition)))
asns <- sub$list_role_assignments()
expect_is(asns, "data.frame")
asns_lst <- res$list_role_assignments(as_data_frame=FALSE)
expect_is(asns_lst, "list")
expect_true(all(sapply(asns_lst, is_role_assignment)))
asn <- res$add_role_assignment(newsvc_id, "owner")
expect_true(is_role_assignment(asn))
expect_silent(res$remove_role_assignment(asn$name, confirm=FALSE))
})
sub$delete_resource_group(rgname, confirm=FALSE)