modules/mu/clouds/aws/role.rb in cloud-mu-2.0.0.pre.beta2 vs modules/mu/clouds/aws/role.rb in cloud-mu-2.0.0.pre.beta3
- old
+ new
@@ -290,10 +290,16 @@
# @return [Boolean]
def self.isGlobal?
true
end
+ # Denote whether this resource implementation is experiment, ready for
+ # testing, or ready for production use.
+ def self.quality
+ MU::Cloud::BETA
+ end
+
# Remove all roles associated with the currently loaded deployment.
# @param noop [Boolean]: If true, will only print what would be done
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
# @param region [String]: The cloud provider region
# @return [void]
@@ -483,10 +489,46 @@
bindTo("instance_profile", @mu_name)
resp.instance_profile.arn
end
+ # Schema fragment for IAM policy conditions, which some other resource
+ # types may need to import.
+ def self.condition_schema
+ {
+ "items" => {
+ "properties" => {
+ "conditions" => {
+ "type" => "array",
+ "items" => {
+ "type" => "object",
+ "description" => "One or more conditions under which to apply this policy. See also: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html",
+ "required" => ["comparison", "variable", "values"],
+ "properties" => {
+ "comparison" => {
+ "type" => "string",
+ "description" => "A comparison to make, like +DateGreaterThan+ or +IpAddress+."
+ },
+ "variable" => {
+ "type" => "string",
+ "description" => "The variable which we will compare, like +aws:CurrentTime+ or +aws:SourceIp+."
+ },
+ "values" => {
+ "type" => "array",
+ "items" => {
+ "type" => "string",
+ "description" => "Value(s) to which we will compare our variable, like +2013-08-16T15:00:00Z+ or +192.0.2.0/24+."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+
# Cloud-specific configuration properties.
# @param config [MU::Config]: The calling MU::Config object
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
def self.schema(config)
toplevel_required = []
@@ -497,13 +539,15 @@
rescue MuCloudResourceNotImplemented
true
end
}.map { |t| MU::Cloud.resource_types[t][:cfg_name] }.sort
+
schema = {
"tags" => MU::Config.tags_primitive,
"optional_tags" => MU::Config.optional_tags_primitive,
+ "policies" => self.condition_schema,
"import" => {
"items" => {
"description" => "Can be a shorthand reference to a canned IAM policy like +AdministratorAccess+, or a full ARN like +arn:aws:iam::aws:policy/AmazonESCognitoAccess+"
}
},
@@ -609,18 +653,19 @@
end
ok
end
- private
-
- # Convert entries from the cloud-neutral @config['policies'] list into
- # AWS syntax.
- def convert_policies_to_iam
+ # Convert our generic internal representation of access policies into
+ # structures suitable for AWS IAM policy documents.
+ # @param policies [Array<Hash>]: One or more policy chunks
+ # @param deploy_obj [MU::MommaCat]: Deployment object to use when looking up sibling Mu resources
+ # @return [Array<Hash>]
+ def self.genPolicyDocument(policies, deploy_obj: nil)
iam_policies = []
- if @config['policies']
- @config['policies'].each { |policy|
+ if policies
+ policies.each { |policy|
doc = {
"Version" => "2012-10-17",
"Statement" => [
{
"Sid" => policy["name"].gsub(/[^0-9A-Za-z]*/, ""),
@@ -631,31 +676,72 @@
]
}
policy["permissions"].each { |perm|
doc["Statement"].first["Action"] << perm
}
+ if policy["conditions"]
+ doc["Statement"].first["Condition"] ||= {}
+ policy["conditions"].each { |cond|
+ doc["Statement"].first["Condition"][cond['comparison']] = {
+ cond["variable"] => cond["values"]
+ }
+ }
+ end
+ if policy["grant_to"] # XXX factor this with target, they're too similar
+ doc["Statement"].first["Principal"] ||= []
+ policy["grant_to"].each { |grantee|
+ if grantee["type"] and deploy_obj
+ sibling = deploy_obj.findLitterMate(
+ name: grantee["identifier"],
+ type: grantee["type"]
+ )
+ if sibling
+ id = sibling.cloudobj.arn
+ doc["Statement"].first["Principal"] << id
+ else
+ raise MuError, "Couldn't find a #{grantee["type"]} named #{grantee["identifier"]} when generating IAM policy"
+ end
+ else
+ doc["Statement"].first["Principal"] << grantee["identifier"]
+ end
+ }
+ if policy["grant_to"].size == 1
+ doc["Statement"].first["Principal"] = doc["Statement"].first["Principal"].first
+ end
+ end
if policy["targets"]
policy["targets"].each { |target|
- if target["type"]
- sibling = @deploy.findLitterMate(
+ if target["type"] and deploy_obj
+ sibling = deploy_obj.findLitterMate(
name: target["identifier"],
type: target["type"]
)
if sibling
- doc["Statement"].first["Resource"] << sibling.cloudobj.arn
+ id = sibling.cloudobj.arn
+ id += target["path"] if target["path"]
+ doc["Statement"].first["Resource"] << id
else
- raise MuError, "Couldn't find a #{target["entity_type"]} named #{target["identifier"]} when generating IAM policy in role #{@mu_name}"
+ raise MuError, "Couldn't find a #{target["entity_type"]} named #{target["identifier"]} when generating IAM policy"
end
else
+ target["identifier"] += target["path"] if target["path"]
doc["Statement"].first["Resource"] << target["identifier"]
end
}
end
iam_policies << { policy["name"] => doc }
}
end
iam_policies
+ end
+
+ private
+
+ # Convert entries from the cloud-neutral @config['policies'] list into
+ # AWS syntax.
+ def convert_policies_to_iam
+ MU::Cloud::AWS::Role.genPolicyDocument(@config['policies'], deploy_obj: @deploy)
end
def get_tag_params(strip_std = false)
@config['tags'] ||= []