Below is our Policy which we trying to apply
name "Untagged Resources"
rs_pt_ver 20180301
type "policy"
long_description ""
category "Compliance"
severity "medium"
info(
version: "1.14",
provider: "Flexera Cloud Management",
service: "",
policy_set: ""
)
permission "retrieve_resources" do
label "Retrieve Resources"
actions "rs_cm.index","rs_cm.show"
resources "rs_cm.instances","rs_cm.volumes"
end
permission "tags" do
label "Retrieve and add Tags"
actions "rs_cm.by_resource","rs_cm.multi_add"
resources "rs_cm.tags"
end
##################
# User inputs #
##################
parameter "param_tag_keys" do
category "User Inputs"
label "Tags' Namespace:Keys List"
type "string"
description "Comma-separated list of Tags' Namespace:Keys to audit. For example: \"ec2:project_code\" or \"bu:id\"."
# allow namespace:key or nothing
allowed_pattern /^([a-zA-Z0-9-_]+:[a-zA-Z0-9-_]+,*|)+$/
end
parameter "param_advanced_tag_key" do
category "User Inputs"
label "Tags' Namespace:Keys Advanced List"
type "string"
description 'A JSON string to describe the tag policy configuration. See the README for example'
allowed_pattern /(\{.*\}|)/
end
parameter "param_email" do
label "Email addresses of the recipients you wish to notify"
type "list"
end
# Retrieve all clouds
resources "clouds", type: "rs_cm.clouds"
# Retrieve all operational instances across all clouds
resources "instances_operational", type: "rs_cm.instances" do
iterate @clouds
cloud_href href(iter_item)
filter do
state "operational"
end
tags '*'
end
# Retrieve all provisioned instances across all clouds
resources "instances_provisioned", type: "rs_cm.instances" do
iterate @clouds
cloud_href href(iter_item)
filter do
state "provisioned"
end
tags '*'
end
# Retrieve all running instances across all clouds
resources "instances_running", type: "rs_cm.instances" do
iterate @clouds
cloud_href href(iter_item)
filter do
state "running"
end
tags '*'
end
# Retrieve all volumes across all clouds
resources "volumes", type: "rs_cm.volumes" do
iterate @clouds
cloud_href href(iter_item)
tags '*'
end
datasource "clouds" do
iterate @clouds
field "href", href(iter_item)
field "type", val(iter_item,'cloud_type')
field "name", val(iter_item,'name')
end
datasource "instances_operational" do
iterate @instances_operational
field "href", href(iter_item)
field "id", val(iter_item,'resource_uid')
field "name", val(iter_item,'name')
field "state", val(iter_item,'state')
field "tags", val(iter_item,'tags')
field "type", "instances"
end
datasource "instances_running" do
iterate @instances_running
field "href", href(iter_item)
field "id", val(iter_item,'resource_uid')
field "name", val(iter_item,'name')
field "state", val(iter_item,'state')
field "tags", val(iter_item,'tags')
field "type", "instances"
end
datasource "instances_provisioned" do
iterate @instances_provisioned
field "href", href(iter_item)
field "id", val(iter_item,'resource_uid')
field "name", val(iter_item,'name')
field "state", val(iter_item,'state')
field "tags", val(iter_item,'tags')
field "type", "instances"
end
datasource "volumes" do
iterate @volumes
field "href", href(iter_item)
field "id", val(iter_item,'resource_uid')
field "name", val(iter_item,'name')
field "state", val(iter_item,'status')
field "tags", val(iter_item,'tags')
field "type", "volumes"
end
datasource "resources" do
run_script $merge_resources, $instances_operational,$instances_running,$instances_provisioned,$volumes
end
script "merge_resources", type: "javascript" do
parameters "instances_operational","instances_running","instances_provisioned", "volumes"
result "resources"
code <<-EOS
var resources = []
for (i = 0; i < instances_operational.length; i++) {
resources.push(instances_operational[i])
}
for (i = 0; i < instances_running.length; i++) {
resources.push(instances_running[i])
}
for (i = 0; i < instances_provisioned.length; i++) {
resources.push(instances_provisioned[i])
}
for (i = 0; i < volumes.length; i++) {
resources.push(volumes[i])
}
EOS
end
auth "rs", type: "rightscale"
# get a tagset for all resources
datasource "resource_tags" do
request do
auth $rs
verb "POST"
host rs_cm_host
path "/api/tags/by_resource"
header "X-Api-Version", "1.5"
body_field "resource_hrefs", vals($resources,"href")
end
end
datasource "filtered_resources" do
run_script $filter_resources, $resources, $clouds,$param_tag_keys,$param_advanced_tag_key
end
script "filter_resources", type: "javascript" do
parameters "resources","clouds","param_tag_keys","param_advanced_tag_key"
result "filtered_resources"
code <<-EOS
// This is the list of filtered volumes.
var filtered_resources = [];
var tag_keys_array = []
if ( param_tag_keys !== '' ){
tag_keys_array = param_tag_keys.split(',')
}
var validate_tags_object={}
// keys from JSON
var advanced_tag_keys=[]
// check for param_advanced_tag_key and parse the json
if ( param_advanced_tag_key !== '') {
validate_tags_object = JSON.parse(param_advanced_tag_key)
advanced_tag_keys = _.keys(validate_tags_object)
for (var i = 0; i < advanced_tag_keys.length; i++) {
tag_keys_array.push(advanced_tag_keys[i])
}
}
tag_keys_array = _.uniq(tag_keys_array)
// create a map of clouds with href key to get type and name
var cloud_map = {}
for (var i = 0; i < clouds.length; i++) {
var cloud = clouds[i]
cloud_map[cloud['href']]={'type': cloud['type'],'name': cloud['name']}
}
// Go through all the resources and filter the ones that don't
// comply with the tag rules.
for (var i = 0; i < resources.length; i++) {
var res = resources[i]
var res_tags = []
var invalid_tags =[]
var bad = false
// Tags is an array of hashes each with just 'name'. Let's convert
// them to an array of strings.
for (var j = 0; j < res['tags'].length; j++) {
tag = res['tags'][j]
tag_key = tag.split("=")[0]
tag_value = tag.split("=")[1]
if ( validate_tags_object[tag_key] && validate_tags_object[tag_key]['validation-type']==='string' ){
if ( validate_tags_object[tag_key]['validation'] !== tag_value ){
bad=true
invalid_tags.push(tag)
}
}
if ( validate_tags_object[tag_key] && validate_tags_object[tag_key]['validation-type'] === 'array' ){
if ( validate_tags_object[tag_key]['validation'].indexOf(tag_value) === -1 ){
bad=true
invalid_tags.push(tag)
}
}
if ( validate_tags_object[tag_key] && validate_tags_object[tag_key]['validation-type'] === 'regex'){
if ( tag_value.search(validate_tags_object[tag_key]['validation']) === -1 ){
bad=true
invalid_tags.push(tag)
}
}
res_tags.push(tag_key)
}
// Determines whether this resource is properly tagged
var missing_tags = []
if ( _.intersection(tag_keys_array, res_tags).length != tag_keys_array.length ) {
bad = true;
//find the tags missing from the resource
missing_tags=_.difference(tag_keys_array, res_tags)
}
// create cloud_href from resource href
var split = res['href'].split('/')
var index = res['href'].indexOf('/'+split[4])
var cloud_href = res['href'].substring(0,index)
// update resource array with resources that are missing tags
if ( bad ) {
var missing_tags_list = "";
var invalid_tags_list = "";
for(var prop in missing_tags){
missing_tags_list = missing_tags_list +prop+":"+missing_tags[prop]+", "
}
for(var prop in invalid_tags){
invalid_tags_list = invalid_tags_list+prop+":"+invalid_tags[prop]+", "
}
filtered_resources.push({
id: res['id'],
name: res['name'],
state: res['state'],
href: res['href'],
type: res['type'],
cloud_name: cloud_map[cloud_href]['name'],
cloud_type: cloud_map[cloud_href]['type'],
missing_tags: missing_tags,
invalid_tags: invalid_tags,
})
}
};
EOS
end
escalation "email" do
automatic true
label "Send Email"
description "Send incident email"
email $param_email
end
policy "untagged_resources_policy" do
validate $filtered_resources do
summary_template "{{ rs_project_name }} (Account ID: {{ rs_project_id }}): {{ len data }} Untagged Resources Found"
export do
resource_level true
field "cloud_name" do
label "Cloud Name"
end
field "cloud_type" do
label "Cloud Type"
end
field "name" do
label "Name"
end
field "type" do
label "Type"
end
field "state" do
label "State"
end
field "href" do
label "Href"
end
field "missing_tags" do
label "Missing Tags"
end
field "invalid_tags" do
label "Invalid Tags"
end
field "id" do
label "ID"
end
end
escalate $escalate_resources
escalate $email
check eq(size(data), 0)
resolve $resolve_resources
end
end
define sys_log($subject, $detail) do
if $$debug
rs_cm.audit_entries.create(
notify: "None",
audit_entry: {
auditee_href: @@account,
summary: "Untagged Resources Policy "+ $subject,
detail: $detail
}
)
end
end