* changes to enable auth with CLI app id

* api for persistent logins

* dev version number

* typo

* add documentation

* update docs to use get_az_login

* update mds

* allow new login flow to use svc principal

* fix delete_az_login

* more fixups

* fix list_az_logins

* update news

* update intro

* add badges

* az_login -> azure_login

* doc fix

* cleanup

* document

* document fixup

* update tests

* rationalise auth arguments: resource_host first arg, auth_type default based on pwd

* fix vignette img links
This commit is contained in:
Hong Ooi 2018-12-26 15:15:31 +11:00 коммит произвёл GitHub
Родитель 9c90892421
Коммит 5ab610fd8e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 371 добавлений и 57 удалений

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

@ -3,6 +3,8 @@ Title: Interface to 'Azure Resource Manager'
Version: 1.0.0.9000 Version: 1.0.0.9000
Authors@R: c( Authors@R: c(
person("Hong", "Ooi", , "hongooi@microsoft.com", role = c("aut", "cre")), person("Hong", "Ooi", , "hongooi@microsoft.com", role = c("aut", "cre")),
person("Scott", "Holden", , role = "ctb", comment = "Advice on AAD authentication"),
person("Chris", "Stone", , role = "ctb", comment = "Advice on AAD authentication"),
person("Microsoft", role="cph") person("Microsoft", role="cph")
) )
Description: A lightweight but powerful R interface to the 'Azure Resource Manager' REST API. The package exposes classes and methods for 'OAuth' authentication and working with subscriptions and resource groups. It also provides functionality for creating and deleting 'Azure' resources and deploying templates. While 'AzureRMR' can be used to manage any 'Azure' service, it can also be extended by other packages to provide extra functionality for specific services. Description: A lightweight but powerful R interface to the 'Azure Resource Manager' REST API. The package exposes classes and methods for 'OAuth' authentication and working with subscriptions and resource groups. It also provides functionality for creating and deleting 'Azure' resources and deploying templates. While 'AzureRMR' can be used to manage any 'Azure' service, it can also be extended by other packages to provide extra functionality for specific services.
@ -16,9 +18,11 @@ Imports:
utils, utils,
httr (>= 1.3), httr (>= 1.3),
jsonlite, jsonlite,
R6 R6,
rappdirs
Suggests: Suggests:
knitr, knitr,
testthat testthat,
httpuv
Roxygen: list(markdown=TRUE) Roxygen: list(markdown=TRUE)
RoxygenNote: 6.1.0.9000 RoxygenNote: 6.1.0.9000

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

@ -8,9 +8,12 @@ export(az_subscription)
export(az_template) export(az_template)
export(call_azure_rm) export(call_azure_rm)
export(call_azure_url) export(call_azure_url)
export(create_azure_login)
export(delete_azure_login)
export(format_auth_header) export(format_auth_header)
export(format_public_fields) export(format_public_fields)
export(format_public_methods) export(format_public_methods)
export(get_azure_login)
export(get_azure_token) export(get_azure_token)
export(is_empty) export(is_empty)
export(is_resource) export(is_resource)
@ -18,5 +21,7 @@ export(is_resource_group)
export(is_subscription) export(is_subscription)
export(is_template) export(is_template)
export(is_url) export(is_url)
export(list_azure_logins)
export(named_list) export(named_list)
export(refresh_azure_logins)
importFrom(utils,modifyList) importFrom(utils,modifyList)

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

@ -1,5 +1,11 @@
# AzureRMR 1.0.0.9000 # AzureRMR 1.0.0.9000
## Significant interface changes
* New `create_azure_login`, `get_azure_login` and `delete_azure_login` functions to handle ARM authentication. These will persist the login object across sessions, removing the need to re-authenticate each time. While directly calling `az_rm$new()` will still work, it's recommended to use `create_azure_login` and `get_azure_login` going forward.
## Other changes
* Don't print empty fields for ARM objects. * Don't print empty fields for ARM objects.
* Add optional `etag` field to resource object definition. * Add optional `etag` field to resource object definition.
* Fix `AzureToken` object to never have a `NULL` password field (important to allow devicecode refreshing). * Fix `AzureToken` object to never have a `NULL` password field (important to allow devicecode refreshing).

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

@ -5,6 +5,11 @@ NULL
{ {
azure_api_version="2018-05-01" azure_api_version="2018-05-01"
options(azure_api_version=azure_api_version) options(azure_api_version=azure_api_version)
config_dir <- config_dir()
if(!dir.exists(config_dir))
dir.create(config_dir, recursive=TRUE)
invisible(NULL) invisible(NULL)
} }

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

@ -115,12 +115,12 @@ private=list(
#' #'
#' This extends the OAuth functionality in httr to allow for device code authentication. #' This extends the OAuth functionality in httr to allow for device code authentication.
#' #'
#' @param aad_host URL for your Azure Active Directory host. For the public Azure cloud, this is `https://login.microsoftonline.com/`. #' @param resource_host URL for your resource host. For Resource Manager in the public Azure cloud, this is `https://management.azure.com/`.
#' @param tenant Your tenant ID. #' @param tenant Your tenant ID.
#' @param app Your client/app ID which you registered in AAD. #' @param app Your client/app ID which you registered in AAD.
#' @param auth_type The authentication type, either `"client_credentials"` or `"device_code"`.
#' @param password Your password. Required for `auth_type == "client_credentials"`, ignored for `auth_type == "device_code"`. #' @param password Your password. Required for `auth_type == "client_credentials"`, ignored for `auth_type == "device_code"`.
#' @param resource_host URL for your resource host. For Resource Manager in the public Azure cloud, this is `https://management.azure.com/`. #' @param auth_type The authentication type, either `"client_credentials"` or `"device_code"`. Defaults to the latter if no password is provided, otherwise the former.
#' @param aad_host URL for your Azure Active Directory host. For the public Azure cloud, this is `https://login.microsoftonline.com/`.
#' #'
#' @details #' @details
#' This function does much the same thing as [httr::oauth2.0_token()], but with support for device authentication and with unnecessary options removed. Device authentication removes the need to save a password on your machine. Instead, the server provides you with a code, along with a URL. You then visit the URL in your browser and enter the code, which completes the authentication process. #' This function does much the same thing as [httr::oauth2.0_token()], but with support for device authentication and with unnecessary options removed. Device authentication removes the need to save a password on your machine. Instead, the server provides you with a code, along with a URL. You then visit the URL in your browser and enter the code, which completes the authentication process.
@ -142,10 +142,12 @@ private=list(
#' #'
#' } #' }
#' @export #' @export
get_azure_token=function(aad_host, tenant, app, auth_type=c("client_credentials", "device_code"), get_azure_token=function(resource_host, tenant, app, password=NULL,
password, resource_host) auth_type=if(is.null(password)) "device_code" else "client_credentials",
aad_host="https://login.microsoftonline.com/")
{ {
auth_type <- match.arg(auth_type) tenant <- normalize_tenant(tenant)
base_url <- construct_path(aad_host, tenant) base_url <- construct_path(aad_host, tenant)
if(auth_type == "client_credentials") if(auth_type == "client_credentials")
auth_with_creds(base_url, app, password, resource_host) auth_with_creds(base_url, app, password, resource_host)

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

@ -11,18 +11,20 @@
#' - `get_subscription(id)`: Returns an object representing a subscription. #' - `get_subscription(id)`: Returns an object representing a subscription.
#' #'
#' @section Authentication: #' @section Authentication:
#' To authenticate with ARM, provide the following arguments to the `new` method: #' The best way to authenticate with ARM is probably via the [create_azure_login] and [get_azure_login] functions. With these, you only have to authenticate once, after which your credentials are saved and reused for subsequent sessions.
#'
#' To authenticate with the `az_rm` class directly, provide the following arguments to the `new` method:
#' - `tenant`: Your tenant ID. #' - `tenant`: Your tenant ID.
#' - `app`: Your client/app ID which you registered in Azure Active Directory. #' - `app`: Your client/app ID which you registered in Azure Active Directory.
#' - `auth_type`: Either `"client_credentials"` (the default) or `"device_code"`.
#' - `password`: if `auth_type == "client_credentials"`, your password. #' - `password`: if `auth_type == "client_credentials"`, your password.
#' - `auth_type`: Either `"client_credentials"` or `"device_code"`. Defaults to the latter if no password is provided, otherwise the former.
#' - `host`: your ARM host. Defaults to `https://management.azure.com/`. Change this if you are using a government or private cloud. #' - `host`: your ARM host. Defaults to `https://management.azure.com/`. Change this if you are using a government or private cloud.
#' - `aad_host`: Azure Active Directory host for authentication. Defaults to `https://login.microsoftonline.com/`. Change this if you are using a government or private cloud. #' - `aad_host`: Azure Active Directory host for authentication. Defaults to `https://login.microsoftonline.com/`. Change this if you are using a government or private cloud.
#' - `config_file`: Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI `az ad sp create-for-rbac` command. #' - `config_file`: Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI `az ad sp create-for-rbac` command.
#' - `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. #' - `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 #' @seealso
#' [get_azure_token], [AzureToken], #' [create_azure_login], [get_azure_token], [AzureToken],
#' [Azure Resource Manager overview](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview), #' [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/) #' [REST API reference](https://docs.microsoft.com/en-us/rest/api/resources/)
#' #'
@ -55,7 +57,8 @@ public=list(
token=NULL, token=NULL,
# authenticate and get subscriptions # authenticate and get subscriptions
initialize=function(tenant, app, auth_type="client_credentials", password, initialize=function(tenant, app, password=NULL,
auth_type=if(is.null(password)) "device_code" else "client_credentials",
host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/", host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/",
config_file=NULL, token=NULL) config_file=NULL, token=NULL)
{ {
@ -78,8 +81,8 @@ public=list(
if(!is.null(conf$aad_host)) aad_host <- conf$aad_host if(!is.null(conf$aad_host)) aad_host <- conf$aad_host
} }
self$host <- host self$host <- host
self$tenant <- tenant self$tenant <- normalize_tenant(tenant)
self$token <- get_azure_token(aad_host, tenant, app, auth_type, password, host) self$token <- get_azure_token(self$host, self$tenant, app, password, auth_type, aad_host)
NULL NULL
}, },

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

@ -0,0 +1,176 @@
config_dir <- function()
{
rappdirs::user_config_dir(appname="AzureRMR", appauthor="AzureR", roaming=FALSE)
}
#' Functions to login to Azure Resource Manager
#'
#' @param tenant The Azure Active Directory tenant for which to obtain a login client. Can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a GUID.
#' @param app The app ID to authenticate with.
#' @param password If `auth_type == "client_credentials"`, your password.
#' @param auth_type The type of authentication to use, either "device_code" or "client_credentials". Defaults to the latter if no password is provided, otherwise the former.
#' @param host Your ARM host. Defaults to `https://management.azure.com/`. Change this if you are using a government or private cloud.
#' @param aad_host Azure Active Directory host for authentication. Defaults to `https://login.microsoftonline.com/`. Change this if you are using a government or private cloud.
#' @param config_file Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI `az ad sp create-for-rbac` command.
#' @param refresh For `get_azure_login`, whether to refresh the authentication token on loading the client.
#' @param confirm For `delete_azure_login`, whether to ask for confirmation before deleting.
#' @param ... Other arguments passed to `az_rm$new()`.
#'
#' @details
#' These functions allow you to authenticate with Azure Resource Manager (ARM).
#' - `create_azure_login` creates a login client, using the supplied credentials. You only have to create a login client once per tenant; the resulting object is saved on your machine and reused automatically in subsequent R sessions.
#' - `get_azure_login` will load a previously saved ARM client object for the given tenant. If this is the first time you are logging in for this tenant, the client object is created via `create_login_client`.
#' - `delete_azure_login` deletes the client object for the given tenant from your machine. Note that this doesn't invalidate any client you may be using in your R session.
#' - `list_azure_logins` lists client objects that have been previously saved.
#' - `refresh_azure_logins` refreshes all client objects existing on your machine.
#'
#' `create_azure_login` is roughly equivalent to the Azure CLI command `az login` with no arguments.
#'
#' @return
#' For `create_azure_login` and `get_azure_login`, an object of class `az_rm`, representing the ARM login client. For `list_azure_logins`, a list of such objects.
#'
#' @seealso
#' [az_rm], [Azure CLI documentation](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest)
#'
#' @examples
#' \dontrun{
#'
#' # this will create a Resource Manager client for the AAD tenant 'microsoft.onmicrosoft.com'
#' # only has to be run once per tenant
#' az <- create_azure_login("microsoft", app="{app_id}", password="{password}")
#'
#' # you can also login using credentials in a json file
# az <- create_azure_login(config_file="~/creds.json")
#'
#' # in subsequent sessions, you can retrieve the client without re-authenticating:
#' # authentication details will automatically be refreshed
#' az <- get_azure_login("microsoft")
#'
#' # refresh (renew) authentication details for clients for all tenants
#' refresh_azure_logins()
#'
#' }
#' @rdname azure_login
#' @export
create_azure_login <- function(tenant, app, password=NULL,
auth_type=if(is.null(password)) "device_code" else "client_credentials",
host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/",
config_file=NULL, ...)
{
if(!is.null(config_file))
{
conf <- jsonlite::fromJSON(config_file)
if(!is.null(conf$tenant)) tenant <- conf$tenant
if(!is.null(conf$app)) app <- conf$app
if(!is.null(conf$auth_type)) auth_type <- conf$auth_type
if(!is.null(conf$password)) password <- conf$password
if(!is.null(conf$host)) host <- conf$host
if(!is.null(conf$aad_host)) aad_host <- conf$aad_host
}
tenant <- normalize_tenant(tenant)
message("Creating Azure Active Directory login for tenant '", tenant, "'")
client <- az_rm$new(tenant, app, password, auth_type, host, aad_host, config_file, ...)
save_client(client, tenant)
client
}
#' @rdname azure_login
#' @export
get_azure_login <- function(tenant, ..., refresh=TRUE)
{
tenant <- normalize_tenant(tenant)
login_exists <- file.exists(file.path(config_dir(), tenant))
if(!login_exists)
return(create_azure_login(tenant, ...))
message("Loading Azure Active Directory login for tenant '", tenant, "'")
client <- readRDS(file.path(config_dir(), tenant))
if(refresh)
{
# refresh and save
client$token$refresh()
save_client(client, tenant)
}
client
}
#' @rdname azure_login
#' @export
delete_azure_login <- function(tenant, confirm=TRUE)
{
tenant <- normalize_tenant(tenant)
if(confirm && interactive())
{
yn <- readline(
paste0("Do you really want to delete the Azure Active Directory login for tenant ", tenant, "? (y/N) "))
if(tolower(substr(yn, 1, 1)) != "y")
return(invisible(NULL))
}
file.remove(file.path(config_dir(), tenant))
invisible(NULL)
}
#' @rdname azure_login
#' @export
list_azure_logins <- function()
{
tenants <- dir(config_dir(), full.names=TRUE)
lst <- lapply(tenants, readRDS)
names(lst) <- basename(tenants)
lst
}
#' @rdname azure_login
#' @export
refresh_azure_logins <- function()
{
refresh_and_save <- function(tenant)
{
client <- readRDS(tenant)
client$token$refresh()
save_client(client, basename(tenant))
}
lapply(dir(config_dir(), full.names=TRUE), refresh_and_save)
invisible(NULL)
}
save_client <- function(client, tenant)
{
tenant <- normalize_tenant(tenant)
saveRDS(client, file=file.path(config_dir(), tenant))
invisible(client)
}
normalize_tenant <- function(tenant)
{
# see https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse
# for possible input formats for GUIDs
is_guid <- function(x)
{
grepl("^[0-9a-f]{32}$", x) ||
grepl("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", x) ||
grepl("^\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\}$", x) ||
grepl("^\\([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\)$", x)
}
# check if supplied a guid; if not, check if a fqdn; if not, append '.onmicrosoft.com'
if(is_guid(tenant))
return(tenant)
if(!grepl("\\.", tenant))
tenant <- paste(tenant, "onmicrosoft.com", sep=".")
tenant
}

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

@ -55,8 +55,7 @@
#' \dontrun{ #' \dontrun{
#' #'
#' # recommended way to retrieve a resource group object #' # recommended way to retrieve a resource group object
#' rg <- az_rm$ #' rg <- get_azure_login("myaadtenant")$
#' new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
#' get_subscription("subscription_id")$ #' get_subscription("subscription_id")$
#' get_resource_group("rgname") #' get_resource_group("rgname")
#' #'

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

@ -26,8 +26,7 @@
#' \dontrun{ #' \dontrun{
#' #'
#' # recommended way to retrieve a subscription object #' # recommended way to retrieve a subscription object
#' sub <- az_rm$ #' sub <- get_azure_login("myaadtenant")$
#' new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
#' get_subscription("subscription_id") #' get_subscription("subscription_id")
#' #'
#' # retrieve list of resource group objects under this subscription #' # retrieve list of resource group objects under this subscription

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

@ -8,6 +8,7 @@ AzureRMR is a package for interacting with Azure Resource Manager: authenticate,
You can install the development version from GitHub, via `devtools::install_github("cloudyr/AzureRMR")`. You can install the development version from GitHub, via `devtools::install_github("cloudyr/AzureRMR")`.
## Before you begin ## Before you begin
To use AzureRMR, you must create and register a service principal with Azure Active Directory. This is a one-time task, and the easiest method is to use the Azure cloud shell. To use AzureRMR, you must create and register a service principal with Azure Active Directory. This is a one-time task, and the easiest method is to use the Azure cloud shell.
@ -26,12 +27,21 @@ To use AzureRMR, you must create and register a service principal with Azure Act
If you want to allow access at something other than subscription level, you can use the `--scopes` argument in place of `--subscription`. For example, to restrict AzureRMR to only the "AnalyticsRG" resource group: `az ad sp create-for-rbac --scopes /subscriptions/{your-subscription-ID}/resourceGroups/AnalyticsRG`. If you want to allow access at something other than subscription level, you can use the `--scopes` argument in place of `--subscription`. For example, to restrict AzureRMR to only the "AnalyticsRG" resource group: `az ad sp create-for-rbac --scopes /subscriptions/{your-subscription-ID}/resourceGroups/AnalyticsRG`.
## Authentication
Under the hood, AzureRMR uses a similar authentication process to the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest). The first time you authenticate with a given Azure Active Directory tenant, you call `create_azure_login()` and supply your tenant, app ID and password. The resulting Resource Manager client object is saved on your machine, and can be retrieved in subsequent R sessions with `get_azure_login("{tenant}")`. AzureRMR will automatically refresh your credentials so you don't have to re-authenticate.
## Sample workflow ## Sample workflow
```r ```r
library(AzureRMR) library(AzureRMR)
az <- az_rm$new(tenant="{tenant_id}", app="{app_id}", password="{password}") # authenticate with Azure AD:
# - on first login to this client, call create_azure_login(...)
# - on subsequent logins, call get_azure_login("myaadtenant")
az <- create_azure_login("myaadtenant.onmicrosoft.com", app="app_id", password="password")
# get a subscription and resource group # get a subscription and resource group
sub <- az$get_subscription("{subscription_id}") sub <- az$get_subscription("{subscription_id}")

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

@ -73,8 +73,7 @@ To create/deploy a new resource, specify any extra parameters that the provider
\dontrun{ \dontrun{
# recommended way to retrieve a resource group object # recommended way to retrieve a resource group object
rg <- az_rm$ rg <- get_azure_login("myaadtenant")$
new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
get_subscription("subscription_id")$ get_subscription("subscription_id")$
get_resource_group("rgname") get_resource_group("rgname")

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

@ -22,12 +22,14 @@ Base class for interacting with Azure Resource Manager.
\section{Authentication}{ \section{Authentication}{
To authenticate with ARM, provide the following arguments to the \code{new} method: The best way to authenticate with ARM is probably via the \link{create_azure_login} and \link{get_azure_login} functions. With these, you only have to authenticate once, after which your credentials are saved and reused for subsequent sessions.
To authenticate with the \code{az_rm} class directly, provide the following arguments to the \code{new} method:
\itemize{ \itemize{
\item \code{tenant}: Your tenant ID. \item \code{tenant}: Your tenant ID.
\item \code{app}: Your client/app ID which you registered in Azure Active Directory. \item \code{app}: Your client/app ID which you registered in Azure Active Directory.
\item \code{auth_type}: Either \code{"client_credentials"} (the default) or \code{"device_code"}.
\item \code{password}: if \code{auth_type == "client_credentials"}, your password. \item \code{password}: if \code{auth_type == "client_credentials"}, your password.
\item \code{auth_type}: Either \code{"client_credentials"} or \code{"device_code"}. Defaults to the latter if no password is provided, otherwise the former.
\item \code{host}: your ARM host. Defaults to \code{https://management.azure.com/}. Change this if you are using a government or private cloud. \item \code{host}: your ARM host. Defaults to \code{https://management.azure.com/}. Change this if you are using a government or private cloud.
\item \code{aad_host}: Azure Active Directory host for authentication. Defaults to \code{https://login.microsoftonline.com/}. Change this if you are using a government or private cloud. \item \code{aad_host}: Azure Active Directory host for authentication. Defaults to \code{https://login.microsoftonline.com/}. Change this if you are using a government or private cloud.
\item \code{config_file}: Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI \code{az ad sp create-for-rbac} command. \item \code{config_file}: Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI \code{az ad sp create-for-rbac} command.
@ -56,7 +58,7 @@ az$get_subscription("subscription_id")
} }
} }
\seealso{ \seealso{
\link{get_azure_token}, \link{AzureToken}, \link{create_azure_login}, \link{get_azure_token}, \link{AzureToken},
\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/azure/azure-resource-manager/resource-group-overview}{Azure Resource Manager overview},
\href{https://docs.microsoft.com/en-us/rest/api/resources/}{REST API reference} \href{https://docs.microsoft.com/en-us/rest/api/resources/}{REST API reference}
} }

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

@ -35,8 +35,7 @@ Generally, the easiest way to create a subscription object is via the \code{get_
\dontrun{ \dontrun{
# recommended way to retrieve a subscription object # recommended way to retrieve a subscription object
sub <- az_rm$ sub <- get_azure_login("myaadtenant")$
new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
get_subscription("subscription_id") get_subscription("subscription_id")
# retrieve list of resource group objects under this subscription # retrieve list of resource group objects under this subscription

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

@ -0,0 +1,84 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/az_login.R
\name{create_azure_login}
\alias{create_azure_login}
\alias{get_azure_login}
\alias{delete_azure_login}
\alias{list_azure_logins}
\alias{refresh_azure_logins}
\title{Functions to login to Azure Resource Manager}
\usage{
create_azure_login(tenant, app, password = NULL, auth_type = if
(is.null(password)) "device_code" else "client_credentials",
host = "https://management.azure.com/",
aad_host = "https://login.microsoftonline.com/", config_file = NULL,
...)
get_azure_login(tenant, ..., refresh = TRUE)
delete_azure_login(tenant, confirm = TRUE)
list_azure_logins()
refresh_azure_logins()
}
\arguments{
\item{tenant}{The Azure Active Directory tenant for which to obtain a login client. Can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a GUID.}
\item{app}{The app ID to authenticate with.}
\item{password}{If \code{auth_type == "client_credentials"}, your password.}
\item{auth_type}{The type of authentication to use, either "device_code" or "client_credentials". Defaults to the latter if no password is provided, otherwise the former.}
\item{host}{Your ARM host. Defaults to \code{https://management.azure.com/}. Change this if you are using a government or private cloud.}
\item{aad_host}{Azure Active Directory host for authentication. Defaults to \code{https://login.microsoftonline.com/}. Change this if you are using a government or private cloud.}
\item{config_file}{Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI \code{az ad sp create-for-rbac} command.}
\item{...}{Other arguments passed to \code{az_rm$new()}.}
\item{refresh}{For \code{get_azure_login}, whether to refresh the authentication token on loading the client.}
\item{confirm}{For \code{delete_azure_login}, whether to ask for confirmation before deleting.}
}
\value{
For \code{create_azure_login} and \code{get_azure_login}, an object of class \code{az_rm}, representing the ARM login client. For \code{list_azure_logins}, a list of such objects.
}
\description{
Functions to login to Azure Resource Manager
}
\details{
These functions allow you to authenticate with Azure Resource Manager (ARM).
\itemize{
\item \code{create_azure_login} creates a login client, using the supplied credentials. You only have to create a login client once per tenant; the resulting object is saved on your machine and reused automatically in subsequent R sessions.
\item \code{get_azure_login} will load a previously saved ARM client object for the given tenant. If this is the first time you are logging in for this tenant, the client object is created via \code{create_login_client}.
\item \code{delete_azure_login} deletes the client object for the given tenant from your machine. Note that this doesn't invalidate any client you may be using in your R session.
\item \code{list_azure_logins} lists client objects that have been previously saved.
\item \code{refresh_azure_logins} refreshes all client objects existing on your machine.
}
\code{create_azure_login} is roughly equivalent to the Azure CLI command \code{az login} with no arguments.
}
\examples{
\dontrun{
# this will create a Resource Manager client for the AAD tenant 'microsoft.onmicrosoft.com'
# only has to be run once per tenant
az <- create_azure_login("microsoft", app="{app_id}", password="{password}")
# you can also login using credentials in a json file
# in subsequent sessions, you can retrieve the client without re-authenticating:
# authentication details will automatically be refreshed
az <- get_azure_login("microsoft")
# refresh (renew) authentication details for clients for all tenants
refresh_azure_logins()
}
}
\seealso{
\link{az_rm}, \href{https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest}{Azure CLI documentation}
}

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

@ -4,22 +4,22 @@
\alias{get_azure_token} \alias{get_azure_token}
\title{Generate an Azure OAuth token} \title{Generate an Azure OAuth token}
\usage{ \usage{
get_azure_token(aad_host, tenant, app, get_azure_token(resource_host, tenant, app, password = NULL,
auth_type = c("client_credentials", "device_code"), password, auth_type = if (is.null(password)) "device_code" else
resource_host) "client_credentials", aad_host = "https://login.microsoftonline.com/")
} }
\arguments{ \arguments{
\item{aad_host}{URL for your Azure Active Directory host. For the public Azure cloud, this is \code{https://login.microsoftonline.com/}.} \item{resource_host}{URL for your resource host. For Resource Manager in the public Azure cloud, this is \code{https://management.azure.com/}.}
\item{tenant}{Your tenant ID.} \item{tenant}{Your tenant ID.}
\item{app}{Your client/app ID which you registered in AAD.} \item{app}{Your client/app ID which you registered in AAD.}
\item{auth_type}{The authentication type, either \code{"client_credentials"} or \code{"device_code"}.}
\item{password}{Your password. Required for \code{auth_type == "client_credentials"}, ignored for \code{auth_type == "device_code"}.} \item{password}{Your password. Required for \code{auth_type == "client_credentials"}, ignored for \code{auth_type == "device_code"}.}
\item{resource_host}{URL for your resource host. For Resource Manager in the public Azure cloud, this is \code{https://management.azure.com/}.} \item{auth_type}{The authentication type, either \code{"client_credentials"} or \code{"device_code"}. Defaults to the latter if no password is provided, otherwise the former.}
\item{aad_host}{URL for your Azure Active Directory host. For the public Azure cloud, this is \code{https://login.microsoftonline.com/}.}
} }
\description{ \description{
This extends the OAuth functionality in httr to allow for device code authentication. This extends the OAuth functionality in httr to allow for device code authentication.

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

@ -28,3 +28,32 @@ test_that("Authentication works",
expect_is(az3, "az_rm") expect_is(az3, "az_rm")
expect_true(is_azure_token(az3$token)) expect_true(is_azure_token(az3$token))
}) })
test_that("Persistent authentication works",
{
expect_true(is.null(delete_azure_login(tenant, confirm=FALSE)))
expect_true(all(names(list_azure_logins()) != tenant))
login_dirs <- rappdirs::user_config_dir("AzureRMR", "AzureR", roaming=FALSE)
expect_true(all(dir(login_dirs) != tenant))
az <- create_azure_login(tenant=tenant, app=app, password=password)
expect_is(az, "az_rm")
expect_true(length(dir(login_dirs, pattern=tenant)) == 1)
expect_true(is.null(delete_azure_login(tenant, confirm=FALSE)))
expect_true(all(names(list_azure_logins()) != tenant))
creds <- tempfile(fileext=".json")
writeLines(jsonlite::toJSON(list(tenant=tenant, app=app, password=password)), creds)
az2 <- create_azure_login(tenant=tenant, app=app, password=password)
expect_is(az2, "az_rm")
expect_true(length(dir(login_dirs, pattern=tenant)) == 1)
expect_true(az$tenant == az2$tenant && az$tenant == tenant)
az3 <- get_azure_login(tenant)
expect_true(az$tenant == az3$tenant)
})

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

@ -22,7 +22,7 @@ As a general-purpose interface to Azure Resource Manager (ARM), you can use Azur
## Before you begin ## Before you begin
To use AzureRMR, you must create and register a _service principal_ with Azure Active Directory. This is a one-time task, and the easiest method is to use the Azure cloud shell. To use AzureRMR, you must create and register a service principal with Azure Active Directory. This is a one-time task, and the easiest method is to use the Azure cloud shell.
- In the Azure Portal (https://portal.azure.com/), click on the Cloud Shell icon: - In the Azure Portal (https://portal.azure.com/), click on the Cloud Shell icon:
@ -36,42 +36,39 @@ To use AzureRMR, you must create and register a _service principal_ with Azure A
- Record your tenant ID, app ID, and password. - Record your tenant ID, app ID, and password.
This will authorise your service principal to work with objects within a single subscription. If you want to add more subscriptions, you can do so via the Portal. Go to the Subscriptions pane, click on the subscription you want to add, then under "Access Control (IAM)", fill in the details for your service principal and the type of access it to have (typically "Contributor" is good enough).
If you want to allow access at something other than subscription level, you can use the `--scopes` argument in place of `--subscription`. For example, to restrict AzureRMR to only the "AnalyticsRG" resource group: `az ad sp create-for-rbac --scopes /subscriptions/{your-subscription-ID}/resourceGroups/AnalyticsRG`. If you want to allow access at something other than subscription level, you can use the `--scopes` argument in place of `--subscription`. For example, to restrict AzureRMR to only the "AnalyticsRG" resource group: `az ad sp create-for-rbac --scopes /subscriptions/{your-subscription-ID}/resourceGroups/AnalyticsRG`.
## Logging in ## Authentication
Let's look at a sample workflow involving AzureRMR. The first thing to do is authenticate with Azure. AzureRMR supports various ways of authenticating. You can supply a password (which is the default), or if your service principal requires it, you can use the [device code flow](https://www.oauth.com/oauth2-servers/device-flow/token-request/). With the latter, AzureRMR will display a code, and prompt you to visit a login site in your browser. You then enter the code on the site, which completes the process. Let's look at a sample workflow involving AzureRMR.
Finally, any authentication arguments can also be supplied in a JSON file, specified via the `config_file` argument. In particular, the output from the cloud shell command used to create the service principal can be used here. Under the hood, AzureRMR uses a similar authentication process to the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest). The first time you authenticate with a given Azure Active Directory tenant, you call `create_azure_login()` and supply your tenant, app ID and password. The resulting Resource Manager client object is saved on your machine, and can be retrieved in subsequent R sessions with `get_azure_login("{tenant}")`. AzureRMR will automatically refresh your credentials so you don't have to re-authenticate.
```{r, eval=FALSE} ```{r, eval=FALSE}
# authenticate with a password library(AzureRMR)
az <- az_rm$new(tenant="xxx-xxx-xxx",
app="yyy-yyy-yyy",
password="{your-password}")
# authenticate with device code: R will display a code to enter in your browser # if this is the first time you're logging in to this tenant
az2 <- az_rm$new(tenant="xxx-xxx-xxx", az <- create_azure_login("myaadtenant.onmicrosoft.com", app="app_id", password="password")
app="zzz-zzz-zzz",
auth_type="device")
# authenticate with credentials stored in a JSON file # for subsequent sessions
az3 <- az_rm$new(config_file="creds.json") az <- get_azure_login("myaadtenant")
# you can also list the tenants that you've previously authenticated with
list_azure_logins()
``` ```
## Subscriptions and resource groups ## Subscriptions and resource groups
AzureRMR allows you to work with your subscriptions and resource groups. Note that if you created your service principal via the cloud shell, as described in this vignette, you probably only have access to one subscription. Regardless, you can list all subscriptions that you can work with: AzureRMR allows you to work with your subscriptions and resource groups. Note that if you created your service principal via the cloud shell, as described in this vignette, you probably only have access to one subscription. Regardless, you can list all subscriptions that you can work with:
```{r, eval=FALSE} ```{r, eval=FALSE}
# all subscriptions associated with this app # all subscriptions
az$list_subscriptions() az$list_subscriptions()
#$`5710aa44-281f-49fe-bfa6-69e66bb55b11` #$`5710aa44-281f-49fe-bfa6-69e66bb55b11`
#<Azure subscription 5710aa44-281f-49fe-bfa6-69e66bb55b11> #<Azure subscription 5710aa44-281f-49fe-bfa6-69e66bb55b11>
# authorization_source: Legacy # authorization_source: RoleBased
# name: Visual Studio Ultimate with MSDN # name: Visual Studio Ultimate with MSDN
# policies: list(locationPlacementId, quotaId, spendingLimit) # policies: list(locationPlacementId, quotaId, spendingLimit)
# state: Enabled # state: Enabled
@ -99,7 +96,7 @@ Notice that AzureRMR is based on R6 classes, where methods are part of the objec
The `list_subscriptions()` call returns a list of subscription objects. You can retrieve the details for a single subscription with `get_subscription`: The `list_subscriptions()` call returns a list of subscription objects. You can retrieve the details for a single subscription with `get_subscription`:
```{r, eval=FALSE} ```{r, eval=FALSE}
# get a subscription and resource group # get a subscription
(sub1 <- az$get_subscription("5710aa44-281f-49fe-bfa6-69e66bb55b11")) (sub1 <- az$get_subscription("5710aa44-281f-49fe-bfa6-69e66bb55b11"))
#<Azure subscription 5710aa44-281f-49fe-bfa6-69e66bb55b11> #<Azure subscription 5710aa44-281f-49fe-bfa6-69e66bb55b11>
# authorization_source: Legacy # authorization_source: Legacy
@ -119,9 +116,7 @@ A subscription object in turn has methods to get, create and delete resource gro
#<Azure resource group rdev1> #<Azure resource group rdev1>
# id: /subscriptions/5710aa44-281f-49fe-bfa6-69e66bb55b11/resourceGroups/rdev1 # id: /subscriptions/5710aa44-281f-49fe-bfa6-69e66bb55b11/resourceGroups/rdev1
# location: australiaeast # location: australiaeast
# managed_by: NULL
# properties: list(provisioningState) # properties: list(provisioningState)
# tags: NULL
#--- #---
# Methods: # Methods:
# check, create_resource, delete, delete_resource, delete_template, deploy_template, get_resource, # check, create_resource, delete, delete_resource, delete_template, deploy_template, get_resource,
@ -140,12 +135,9 @@ Methods for working with resources and templates are exposed as part of the `az_
(stor <- rg$get_resource(type="Microsoft.Storage/storageServices", name="rdevstor1")) (stor <- rg$get_resource(type="Microsoft.Storage/storageServices", name="rdevstor1"))
#<Azure resource Microsoft.Storage/storageAccounts/rdevstor1> #<Azure resource Microsoft.Storage/storageAccounts/rdevstor1>
# id: /subscriptions/5710aa44-281f-49fe-bfa6-69e66bb55b11/resourceGroups/rdev1/providers/Microsoft.Sto ... # id: /subscriptions/5710aa44-281f-49fe-bfa6-69e66bb55b11/resourceGroups/rdev1/providers/Microsoft.Sto ...
# identity: NULL
# is_synced: TRUE # is_synced: TRUE
# kind: Storage # kind: Storage
# location: australiasoutheast # location: australiasoutheast
# managed_by: NULL
# plan: NULL
# properties: list(networkAcls, trustedDirectories, supportsHttpsTrafficOnly, encryption, # properties: list(networkAcls, trustedDirectories, supportsHttpsTrafficOnly, encryption,
# provisioningState, creationTime, primaryEndpoints, primaryLocation, statusOfPrimary) # provisioningState, creationTime, primaryEndpoints, primaryLocation, statusOfPrimary)
# sku: list(name, tier) # sku: list(name, tier)