diff --git a/NAMESPACE b/NAMESPACE
index a4e119a..f159530 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -36,7 +36,9 @@ export(aws_iam_client)
export(aws_policies)
export(aws_policy)
export(aws_policy_attach)
+export(aws_policy_create)
export(aws_policy_detach)
+export(aws_policy_document_create)
export(aws_policy_exists)
export(aws_role)
export(aws_role_create)
diff --git a/R/policies.R b/R/policies.R
index 0a24053..5ee6468 100644
--- a/R/policies.R
+++ b/R/policies.R
@@ -74,6 +74,102 @@ aws_policy_exists <- function(name) {
!is.null(purrr::safely(aws_policy)(name)$result)
}
+#' Create a policy
+#'
+#' @export
+#' @param name (character) a policy name. required
+#' @param document (character) the policy document you want to use
+#' as the content for the new policy. required.
+#' @param path (character) the path for the policy. if not given
+#' default is "/". optional
+#' @param description (character) a friendly description of the policy.
+#' optional. cannot be changed after assigning it
+#' @param tags (character) a vector of tags that you want to attach to
+#' the new IAM policy. Each tag consists of a key name and an associated
+#' value. optional
+#' @return a tibble with policy details
+#' @details see docs
+#' @family policies
+#' @examples \dontrun{
+#' aws_db_rds_list()
+#' aws_policy_document_create()
+#' aws_policy_create("RdsAllow", document = doc)
+#' }
+aws_policy_create <- function(
+ name, document, path = NULL,
+ description = NULL, tags = NULL) {
+ env64$iam$create_policy(
+ PolicyName = name,
+ PolicyDocument = document,
+ Path = path,
+ Description = description,
+ Tags = tags
+ )
+}
+
+#' Create a policy document
+#'
+#' @export
+#' @param region (character) the AWS Region for the DB instance. length==1
+#' @param account_id (character) the AWS account number for the DB instance.
+#' length==1. The user must be in the same account as the account for the
+#' DB instance
+#' @param resource_id (character) the identifier for the DB instance. length==1
+#' @param user (character) a user name that has an IAM account. length>=1
+#' @param action (character) an action. required. see Actions below.
+#' @param effect (character) valid values: "Allow" (default), "Deny". length==1
+#' @param ... named args passed to [jsonlite::toJSON()]
+#' @references # nolint start
+#'
+#' # nolint end
+#' @return a json class string. use [as.character()] to coerce to a regular
+#' string
+#' @note a few document items are hard-coded:
+#' - `Version` is set to 2012-10-17"
+#' - `Action` is set to "rds-db:connect"
+#' @section Actions:
+#' Actions documentation appears to be all over the web. Here's a start:
+#' - S3: # nolint
+#' - EC2: # nolint
+#' - IAM: # nolint
+#' @examplesIf interactive()
+#' ### DB account = user in a database that has access to it
+#' # all DB instances & DB accounts for a AWS account and AWS Region
+#' aws_policy_document_create("us-east-2", "1234567890", "*", "*")
+#' # all DB instances for a AWS account and AWS Region, single DB account
+#' aws_policy_document_create("us-east-2", "1234567890", "*", "jane_doe")
+#' # single DB instasnce, single DB account
+#' aws_policy_document_create(
+#' "us-east-2",
+#' "1234567890", "db-ABCDEFGHIJKL01234", "jane_doe"
+#' )
+#' # single DB instance, many users
+#' aws_policy_document_create(
+#' region = "us-east-2",
+#' account_id = "1234567890",
+#' resource_id = "db-ABCDEFGHIJKL01234",
+#' user = c("jane_doe", "mary_roe"),
+#' action = "rds-db:connect"
+#' )
+aws_policy_document_create <- function(
+ region, account_id, resource_id, user,
+ action, effect = "Allow", ...) {
+ resource <- glue(
+ "arn:aws:rds-db:{region}:{account_id}:dbuser:{resource_id}/{user}"
+ )
+ doc <- list(
+ Version = "2012-10-17",
+ Statement = list(
+ list(
+ Effect = effect,
+ Action = action,
+ Resource = resource
+ )
+ )
+ )
+ jsonlite::toJSON(doc, auto_unbox = TRUE, ...)
+}
+
#' Convert a policy name to a policy ARN
#'
#' @export
diff --git a/man/as_policy_arn.Rd b/man/as_policy_arn.Rd
index 78f0ac5..3dce3d4 100644
--- a/man/as_policy_arn.Rd
+++ b/man/as_policy_arn.Rd
@@ -33,6 +33,7 @@ as_policy_arn("AmazonRDSDataFullAccess")
Other policies:
\code{\link{aws_policies}()},
\code{\link{aws_policy_attach}()},
+\code{\link{aws_policy_create}()},
\code{\link{aws_policy_detach}()},
\code{\link{aws_policy_exists}()},
\code{\link{aws_policy}()}
diff --git a/man/aws_policies.Rd b/man/aws_policies.Rd
index e66f238..5084a5e 100644
--- a/man/aws_policies.Rd
+++ b/man/aws_policies.Rd
@@ -34,6 +34,7 @@ aws_policies(refresh = TRUE)
Other policies:
\code{\link{as_policy_arn}()},
\code{\link{aws_policy_attach}()},
+\code{\link{aws_policy_create}()},
\code{\link{aws_policy_detach}()},
\code{\link{aws_policy_exists}()},
\code{\link{aws_policy}()}
diff --git a/man/aws_policy.Rd b/man/aws_policy.Rd
index 9995b5c..b687040 100644
--- a/man/aws_policy.Rd
+++ b/man/aws_policy.Rd
@@ -29,6 +29,7 @@ Other policies:
\code{\link{as_policy_arn}()},
\code{\link{aws_policies}()},
\code{\link{aws_policy_attach}()},
+\code{\link{aws_policy_create}()},
\code{\link{aws_policy_detach}()},
\code{\link{aws_policy_exists}()}
}
diff --git a/man/aws_policy_attach.Rd b/man/aws_policy_attach.Rd
index e01d4a8..36e1270 100644
--- a/man/aws_policy_attach.Rd
+++ b/man/aws_policy_attach.Rd
@@ -32,6 +32,7 @@ aws_user()$attached_policies
Other policies:
\code{\link{as_policy_arn}()},
\code{\link{aws_policies}()},
+\code{\link{aws_policy_create}()},
\code{\link{aws_policy_detach}()},
\code{\link{aws_policy_exists}()},
\code{\link{aws_policy}()}
diff --git a/man/aws_policy_create.Rd b/man/aws_policy_create.Rd
new file mode 100644
index 0000000..5d05c20
--- /dev/null
+++ b/man/aws_policy_create.Rd
@@ -0,0 +1,50 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/policies.R
+\name{aws_policy_create}
+\alias{aws_policy_create}
+\title{Create a policy}
+\usage{
+aws_policy_create(name, document, path = NULL, description = NULL, tags = NULL)
+}
+\arguments{
+\item{name}{(character) a policy name. required}
+
+\item{document}{(character) the policy document you want to use
+as the content for the new policy. required.}
+
+\item{path}{(character) the path for the policy. if not given
+default is "/". optional}
+
+\item{description}{(character) a friendly description of the policy.
+optional. cannot be changed after assigning it}
+
+\item{tags}{(character) a vector of tags that you want to attach to
+the new IAM policy. Each tag consists of a key name and an associated
+value. optional}
+}
+\value{
+a tibble with policy details
+}
+\description{
+Create a policy
+}
+\details{
+see docs \url{https://www.paws-r-sdk.com/docs/iam_create_policy/}
+}
+\examples{
+\dontrun{
+aws_db_rds_list()
+aws_policy_document_create()
+aws_policy_create("RdsAllow", document = doc)
+}
+}
+\seealso{
+Other policies:
+\code{\link{as_policy_arn}()},
+\code{\link{aws_policies}()},
+\code{\link{aws_policy_attach}()},
+\code{\link{aws_policy_detach}()},
+\code{\link{aws_policy_exists}()},
+\code{\link{aws_policy}()}
+}
+\concept{policies}
diff --git a/man/aws_policy_detach.Rd b/man/aws_policy_detach.Rd
index bc5fbad..df3dd67 100644
--- a/man/aws_policy_detach.Rd
+++ b/man/aws_policy_detach.Rd
@@ -33,6 +33,7 @@ Other policies:
\code{\link{as_policy_arn}()},
\code{\link{aws_policies}()},
\code{\link{aws_policy_attach}()},
+\code{\link{aws_policy_create}()},
\code{\link{aws_policy_exists}()},
\code{\link{aws_policy}()}
}
diff --git a/man/aws_policy_document_create.Rd b/man/aws_policy_document_create.Rd
new file mode 100644
index 0000000..d0b85d1
--- /dev/null
+++ b/man/aws_policy_document_create.Rd
@@ -0,0 +1,84 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/policies.R
+\name{aws_policy_document_create}
+\alias{aws_policy_document_create}
+\title{Create a policy document}
+\usage{
+aws_policy_document_create(
+ region,
+ account_id,
+ resource_id,
+ user,
+ action,
+ effect = "Allow",
+ ...
+)
+}
+\arguments{
+\item{region}{(character) the AWS Region for the DB instance. length==1}
+
+\item{account_id}{(character) the AWS account number for the DB instance.
+length==1. The user must be in the same account as the account for the
+DB instance}
+
+\item{resource_id}{(character) the identifier for the DB instance. length==1}
+
+\item{user}{(character) a user name that has an IAM account. length>=1}
+
+\item{action}{(character) an action. required. see Actions below.}
+
+\item{effect}{(character) valid values: "Allow" (default), "Deny". length==1}
+
+\item{...}{named args passed to \code{\link[jsonlite:fromJSON]{jsonlite::toJSON()}}}
+}
+\value{
+a json class string. use \code{\link[=as.character]{as.character()}} to coerce to a regular
+string
+}
+\description{
+Create a policy document
+}
+\note{
+a few document items are hard-coded:
+\itemize{
+\item \code{Version} is set to 2012-10-17"
+\item \code{Action} is set to "rds-db:connect"
+}
+}
+\section{Actions}{
+
+Actions documentation appears to be all over the web. Here's a start:
+\itemize{
+\item S3: \url{https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazons3.html} # nolint
+\item EC2: \url{https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Operations.html} # nolint
+\item IAM: \url{https://docs.aws.amazon.com/IAM/latest/APIReference/API_Operations.html} # nolint
+}
+}
+
+\examples{
+\dontshow{if (interactive()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
+### DB account = user in a database that has access to it
+# all DB instances & DB accounts for a AWS account and AWS Region
+aws_policy_document_create("us-east-2", "1234567890", "*", "*")
+# all DB instances for a AWS account and AWS Region, single DB account
+aws_policy_document_create("us-east-2", "1234567890", "*", "jane_doe")
+# single DB instasnce, single DB account
+aws_policy_document_create(
+ "us-east-2",
+ "1234567890", "db-ABCDEFGHIJKL01234", "jane_doe"
+)
+# single DB instance, many users
+aws_policy_document_create(
+ region = "us-east-2",
+ account_id = "1234567890",
+ resource_id = "db-ABCDEFGHIJKL01234",
+ user = c("jane_doe", "mary_roe"),
+ action = "rds-db:connect"
+)
+\dontshow{\}) # examplesIf}
+}
+\references{
+#no lint start
+\url{https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html}
+#no lint end
+}
diff --git a/man/aws_policy_exists.Rd b/man/aws_policy_exists.Rd
index ab97fcb..48cab67 100644
--- a/man/aws_policy_exists.Rd
+++ b/man/aws_policy_exists.Rd
@@ -28,6 +28,7 @@ Other policies:
\code{\link{as_policy_arn}()},
\code{\link{aws_policies}()},
\code{\link{aws_policy_attach}()},
+\code{\link{aws_policy_create}()},
\code{\link{aws_policy_detach}()},
\code{\link{aws_policy}()}
}
diff --git a/tests/fixtures/aws_policy_create.yml b/tests/fixtures/aws_policy_create.yml
new file mode 100644
index 0000000..aa0af65
--- /dev/null
+++ b/tests/fixtures/aws_policy_create.yml
@@ -0,0 +1,50 @@
+http_interactions:
+- request:
+ method: post
+ uri: https://iam.amazonaws.com/
+ body:
+ encoding: ''
+ string: Action=CreatePolicy&PolicyDocument=%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%22s3%3AListAllMyBuckets%22%2C%22Resource%22%3A%5B%22arn%3Aaws%3Ards-db%3Aus-east-2%3A1234567890%3Adbuser%3Adb-ABCDEFGHIJKL01234%2Fjane_doe%22%2C%22arn%3Aaws%3Ards-db%3Aus-east-2%3A1234567890%3Adbuser%3Adb-ABCDEFGHIJKL01234%2Fmary_roe%22%5D%7D%5D%7D&PolicyName=MyTestPolicy&Version=2010-05-08
+ headers:
+ User-Agent: paws/0.6.1 (R4.3.3; darwin20; aarch64)
+ Accept: application/xml
+ Content-Type: application/x-www-form-urlencoded; charset=utf-8
+ Content-Length: '433'
+ X-Amz-Date: 20240314T223539Z
+ Authorization: redacted
+ response:
+ status:
+ status_code: 200
+ category: Success
+ reason: OK
+ message: 'Success: (200) OK'
+ headers:
+ date: Thu, 14 Mar 2024 22:35:39 GMT
+ x-amzn-requestid: 9658ed62-7912-4611-8019-b55ba1196714
+ content-type: text/xml
+ content-length: '759'
+ body:
+ encoding: ''
+ file: no
+ string: |
+
+
+
+ 0
+ /
+ 2024-03-14T22:35:40Z
+ v1
+ ANPA22PL7JXXQK37HQPA6
+ true
+ MyTestPolicy
+ 0
+ arn:aws:iam::744061095407:policy/MyTestPolicy
+ 2024-03-14T22:35:40Z
+
+
+
+ 9658ed62-7912-4611-8019-b55ba1196714
+
+
+ recorded_at: 2024-03-14 22:35:40 GMT
+ recorded_with: vcr/1.2.2.91, webmockr/0.9.0
diff --git a/tests/testthat/test-policies.R b/tests/testthat/test-policies.R
index 53db310..7a2debb 100644
--- a/tests/testthat/test-policies.R
+++ b/tests/testthat/test-policies.R
@@ -74,3 +74,42 @@ test_that("aws_policy_detach", {
expect_equal(NROW(user_before$attached_policies), 1)
expect_equal(NROW(user_after$attached_policies), 0)
})
+
+test_that("aws_policy_document_create", {
+ doc1 <- aws_policy_document_create(
+ region = "us-east-2",
+ account_id = "1234567890",
+ resource_id = "*",
+ user = "*",
+ action = "rds-db:connect"
+ )
+ doc1lst <- jsonlite::fromJSON(doc1, FALSE)
+
+ expect_type(doc1, "character")
+ expect_s3_class(doc1, "json")
+ expect_named(doc1lst, c("Version", "Statement"))
+ expect_named(doc1lst$Statement[[1]], c("Effect", "Action", "Resource"))
+ expect_equal(doc1lst$Statement[[1]]$Effect, "Allow")
+ expect_equal(doc1lst$Statement[[1]]$Action, "rds-db:connect")
+})
+
+test_that("aws_policy_create", {
+ withr::local_envvar(c("TESTING64" = TRUE))
+
+ my_doc <- aws_policy_document_create(
+ region = "us-east-2",
+ account_id = "1234567890",
+ resource_id = "db-ABCDEFGHIJKL01234",
+ user = c("jane_doe", "mary_roe"),
+ action = "s3:ListAllMyBuckets"
+ )
+
+ vcr::use_cassette("aws_policy_create", {
+ polisee <- aws_policy_create("MyTestPolicy", document = my_doc)
+ })
+
+ expect_type(polisee, "list")
+ expect_named(polisee, "Policy")
+ expect_equal(polisee$Policy$PolicyName, "MyTestPolicy")
+ expect_match(polisee$Policy$PolicyName, "MyTestPolicy")
+})