148 строки
4.8 KiB
R
148 строки
4.8 KiB
R
metadata_host <- httr::parse_url("http://169.254.169.254")
|
|
inst_api_version <- "2019-02-01"
|
|
att_api_version <- "2018-10-01"
|
|
ev_api_version <- "2017-11-01"
|
|
|
|
|
|
#' Metadata for an Azure VM
|
|
#'
|
|
#' @param nonce For `update_attested_metadata`, an optional string to use as a nonce.
|
|
#' @details
|
|
#' The `instance`, `attested` and `events` environments contain the instance metadata, attested metadata, and scheduled events respectively for a VM running in Azure. `instance` and `attested` are automatically populated when you load the AzureVMmetadata package, or you can manually populate them yourself with the `update_instance_metadata` and `update_attested_metadata` functions. `events` is not populated at package startup, because calling the scheduled event service can require up to several minutes if it is not running already. You can manually populate it with the `update_scheduled_events` function.
|
|
#'
|
|
#' If AzureVMmetadata is loaded in an R session that is _not_ running in an Azure VM, all the metadata environments will be empty.
|
|
#'
|
|
#' @return
|
|
#' The updating functions return the contents of their respective environments as lists, invisibly.
|
|
#' @format
|
|
#' `instance`, `attested` and `events` are environments.
|
|
#' @seealso
|
|
#' [in_azure_vm]
|
|
#'
|
|
#' [Instance metadata service documentation](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service)
|
|
#'
|
|
#' To obtain OAuth tokens from the metadata service, see [AzureAuth::get_managed_token]
|
|
#'
|
|
#' @examples
|
|
#'
|
|
#' ## these will only be meaningful when run in an Azure VM
|
|
#'
|
|
#' # all compute metadata
|
|
#' AzureVMmetadata::instance$compute
|
|
#'
|
|
#' # VM name and ID
|
|
#' AzureVMmetadata::instance$compute$name
|
|
#' AzureVMmetadata::instance$compute$vmId
|
|
#'
|
|
#' # VM resource details: subscription, resource group, resource ID
|
|
#' AzureVMmetadata::instance$compute$subscriptionId
|
|
#' AzureVMmetadata::instance$compute$resourceGroupName
|
|
#' AzureVMmetadata::instance$compute$resourceId
|
|
#'
|
|
#' # all network metadata
|
|
#' AzureVMmetadata::instance$network
|
|
#'
|
|
#' # IPv4 address details (1st network interface)
|
|
#' AzureVMmetadata::instance$network$interface[[1]]$ipv4
|
|
#'
|
|
#' @rdname metadata
|
|
#' @export
|
|
instance <- new.env()
|
|
|
|
#' @rdname metadata
|
|
#' @export
|
|
attested <- new.env()
|
|
|
|
#' @rdname metadata
|
|
#' @export
|
|
events <- new.env()
|
|
|
|
|
|
#' @rdname metadata
|
|
#' @export
|
|
update_instance_metadata <- function()
|
|
{
|
|
metadata_host$path <- "metadata/instance"
|
|
metadata_host$query <- list(`api-version`=att_api_version)
|
|
res <- try(httr::GET(metadata_host, httr::add_headers(metadata=TRUE)), silent=TRUE)
|
|
|
|
if(!inherits(res, "response") || res$status_code > 299)
|
|
return(invisible(NULL))
|
|
|
|
inst <- httr::content(res)
|
|
for(x in names(inst))
|
|
instance[[x]] <- inst[[x]]
|
|
invisible(inst)
|
|
}
|
|
|
|
|
|
#' @rdname metadata
|
|
#' @export
|
|
update_attested_metadata <- function(nonce=NULL)
|
|
{
|
|
metadata_host$path <- "metadata/attested/document"
|
|
metadata_host$query <- list(`api-version`=att_api_version, nonce=nonce)
|
|
res <- try(httr::GET(metadata_host, httr::add_headers(metadata=TRUE)), silent=TRUE)
|
|
|
|
if(!inherits(res, "response") || res$status_code > 299)
|
|
return(invisible(NULL))
|
|
|
|
att <- httr::content(res)
|
|
for(x in names(att))
|
|
attested[[x]] <- att[[x]]
|
|
invisible(att)
|
|
}
|
|
|
|
|
|
#' @rdname metadata
|
|
#' @export
|
|
update_scheduled_events <- function()
|
|
{
|
|
metadata_host$path <- "metadata/scheduledevents"
|
|
metadata_host$query <- list(`api-version`=ev_api_version)
|
|
res <- try(httr::GET(metadata_host, httr::add_headers(metadata=TRUE)), silent=TRUE)
|
|
|
|
if(!inherits(res, "response") || res$status_code > 299)
|
|
return(invisible(NULL))
|
|
|
|
ev <- httr::content(res)
|
|
for(x in names(ev))
|
|
events[[x]] <- ev[[x]]
|
|
invisible(ev)
|
|
}
|
|
|
|
|
|
#' Check if R is running in an Azure VM
|
|
#' @param nonce An optional string to use as a nonce.
|
|
#' @details
|
|
#' These functions check if R is running in an Azure VM by attempting to contact the instance metadata host. `in_azure_vm` simply returns TRUE or FALSE based on whether it succeeds. `get_vm_cert` provides a stronger check, by retrieving the VM's certificate and throwing an error if this is not found. Note that you should still verify the certificate's authenticity before relying on it.
|
|
#' @return
|
|
#' For `in_azure_vm`, a boolean. For `get_vm_cert`, a PKCS-7 certificate object.
|
|
#' @export
|
|
in_azure_vm <- function()
|
|
{
|
|
obj <- try(httr::GET(metadata_host), silent=TRUE)
|
|
inherits(obj, "response") && httr::status_code(obj) == 400
|
|
}
|
|
|
|
|
|
#' @rdname in_azure_vm
|
|
#' @export
|
|
get_vm_cert <- function(nonce=NULL)
|
|
{
|
|
update_attested_metadata(nonce)
|
|
if(is.null(attested$signature))
|
|
stop("No certificate found", call.=FALSE)
|
|
|
|
openssl::read_p7b(openssl::base64_decode(attested$signature))[[1]]
|
|
}
|
|
|
|
|
|
.onLoad <- function(libname, pkgname)
|
|
{
|
|
update_instance_metadata()
|
|
update_attested_metadata()
|
|
}
|
|
|
|
|