зеркало из https://github.com/Azure/AzureRMR.git
basic RBAC support (#15)
* 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:
Родитель
5961b294e6
Коммит
c4b969bcf7
|
@ -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)
|
||||
|
|
4
NEWS.md
4
NEWS.md
|
@ -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
|
||||
|
|
10
R/AzureRMR.R
10
R/AzureRMR.R
|
@ -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/)
|
||||
#'
|
|
@ -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
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")
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
|
|
|
@ -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}
|
|
@ -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.}
|
||||
|
|
|
@ -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)
|
||||
|
Загрузка…
Ссылка в новой задаче