feat(aws): new AWS cloud-containment integration
EC2 + IAM + STS via AWS Query protocol (Signature V4), 9 commands: describe instances/security-groups, authorize/revoke security-group ingress, modify instance security groups (isolate), stop instances, list/update IAM access keys (deactivate compromised key), STS caller identity. Stdlib-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
|||||||
|
id: aws
|
||||||
|
name: AWS
|
||||||
|
version: 1.0.0
|
||||||
|
description: "Amazon Web Services (EC2, IAM, STS) — cloud containment: describe instances and security groups, authorize/revoke security-group ingress rules, change an instance's security groups (isolate), stop instances, and deactivate a compromised IAM access key. AWS Signature V4 authentication; stdlib-only, no extra Python dependencies."
|
||||||
|
changelog: "1.0.0 — Initial release: EC2 describe instances/security-groups, authorize/revoke ingress, modify instance security groups, stop instances; IAM list/update access keys; STS caller identity."
|
||||||
|
category: cloud
|
||||||
|
|
||||||
|
# Per-instance configuration. Requests are signed with AWS Signature V4.
|
||||||
|
# Use an IAM user/role access key with EC2 + IAM permissions. session_token is
|
||||||
|
# only needed for temporary (STS) credentials.
|
||||||
|
config_schema:
|
||||||
|
properties:
|
||||||
|
access_key_id:
|
||||||
|
type: string
|
||||||
|
description: "AWS access key ID"
|
||||||
|
secret_access_key:
|
||||||
|
type: string
|
||||||
|
description: "AWS secret access key"
|
||||||
|
x-soar-sensitive: true
|
||||||
|
region:
|
||||||
|
type: string
|
||||||
|
description: "Default AWS region (e.g. eu-west-1)"
|
||||||
|
default: "us-east-1"
|
||||||
|
session_token:
|
||||||
|
type: string
|
||||||
|
description: "Optional STS session token (for temporary credentials)"
|
||||||
|
x-soar-sensitive: true
|
||||||
|
required:
|
||||||
|
- access_key_id
|
||||||
|
- secret_access_key
|
||||||
|
|
||||||
|
commands:
|
||||||
|
- id: describe_instances
|
||||||
|
name: aws-describe-instances
|
||||||
|
description: "Describe EC2 instances (optionally a single instance by ID)."
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
instance_id: { type: string, description: "Optional instance ID to fetch a single instance" }
|
||||||
|
region: { type: string, description: "Region override" }
|
||||||
|
required: []
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
- id: describe_security_groups
|
||||||
|
name: aws-describe-security-groups
|
||||||
|
description: "Describe EC2 security groups (optionally a single group by ID)."
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
group_id: { type: string, description: "Optional security group ID" }
|
||||||
|
region: { type: string, description: "Region override" }
|
||||||
|
required: []
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
- id: authorize_security_group_ingress
|
||||||
|
name: aws-authorize-security-group-ingress
|
||||||
|
description: "Add an inbound rule to a security group."
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
group_id: { type: string, description: "Security group ID" }
|
||||||
|
protocol: { type: string, description: "IP protocol (tcp, udp, icmp, or -1 for all)" }
|
||||||
|
from_port: { type: number, description: "Start port" }
|
||||||
|
to_port: { type: number, description: "End port" }
|
||||||
|
cidr: { type: string, description: "Source CIDR (e.g. 203.0.113.0/24)" }
|
||||||
|
region: { type: string, description: "Region override" }
|
||||||
|
required: [group_id, protocol, cidr]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
- id: revoke_security_group_ingress
|
||||||
|
name: aws-revoke-security-group-ingress
|
||||||
|
description: "Remove an inbound rule from a security group (containment)."
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
group_id: { type: string, description: "Security group ID" }
|
||||||
|
protocol: { type: string, description: "IP protocol (tcp, udp, icmp, or -1 for all)" }
|
||||||
|
from_port: { type: number, description: "Start port" }
|
||||||
|
to_port: { type: number, description: "End port" }
|
||||||
|
cidr: { type: string, description: "Source CIDR to revoke" }
|
||||||
|
region: { type: string, description: "Region override" }
|
||||||
|
required: [group_id, protocol, cidr]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
- id: modify_instance_security_groups
|
||||||
|
name: aws-modify-instance-security-groups
|
||||||
|
description: "Replace the security groups attached to an instance (e.g. move it to an isolation group)."
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
instance_id: { type: string, description: "Instance ID" }
|
||||||
|
group_ids: { type: string, description: "Comma-separated security group IDs to set" }
|
||||||
|
region: { type: string, description: "Region override" }
|
||||||
|
required: [instance_id, group_ids]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
- id: stop_instances
|
||||||
|
name: aws-stop-instances
|
||||||
|
description: "Stop one or more EC2 instances."
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
instance_ids: { type: string, description: "Comma-separated instance IDs" }
|
||||||
|
force: { type: boolean, description: "Force stop (default false)" }
|
||||||
|
region: { type: string, description: "Region override" }
|
||||||
|
required: [instance_ids]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
- id: list_access_keys
|
||||||
|
name: aws-list-access-keys
|
||||||
|
description: "List a user's IAM access keys."
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
user_name: { type: string, description: "IAM user name (omit to use the calling user)" }
|
||||||
|
required: []
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
- id: update_access_key
|
||||||
|
name: aws-update-access-key
|
||||||
|
description: "Activate or deactivate an IAM access key (deactivate to contain a compromised key)."
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
access_key_id: { type: string, description: "The access key ID to update" }
|
||||||
|
status: { type: string, description: "Active or Inactive" }
|
||||||
|
user_name: { type: string, description: "IAM user name (omit to use the calling user)" }
|
||||||
|
required: [access_key_id, status]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
- id: test_connection
|
||||||
|
name: aws-test-connection
|
||||||
|
description: "Verify credentials via STS GetCallerIdentity (used by the Test button)."
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties: {}
|
||||||
|
required: []
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
group_id = inputs.get("group_id")
|
||||||
|
if not group_id:
|
||||||
|
raise Exception("group_id is required")
|
||||||
|
protocol = inputs.get("protocol")
|
||||||
|
if not protocol:
|
||||||
|
raise Exception("protocol is required")
|
||||||
|
cidr = inputs.get("cidr")
|
||||||
|
if not cidr:
|
||||||
|
raise Exception("cidr is required")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"GroupId": group_id,
|
||||||
|
"IpPermissions.1.IpProtocol": protocol,
|
||||||
|
"IpPermissions.1.IpRanges.1.CidrIp": cidr,
|
||||||
|
}
|
||||||
|
from_port = inputs.get("from_port")
|
||||||
|
if from_port is not None and str(from_port).strip() != "":
|
||||||
|
params["IpPermissions.1.FromPort"] = int(from_port)
|
||||||
|
to_port = inputs.get("to_port")
|
||||||
|
if to_port is not None and str(to_port).strip() != "":
|
||||||
|
params["IpPermissions.1.ToPort"] = int(to_port)
|
||||||
|
|
||||||
|
return ec2("AuthorizeSecurityGroupIngress", params, cfg, inputs)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
instance_id = inputs.get("instance_id")
|
||||||
|
params = {"InstanceId.1": instance_id} if instance_id else {}
|
||||||
|
return ec2("DescribeInstances", params, cfg, inputs)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
group_id = inputs.get("group_id")
|
||||||
|
params = {"GroupId.1": group_id} if group_id else {}
|
||||||
|
return ec2("DescribeSecurityGroups", params, cfg, inputs)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
user_name = inputs.get("user_name")
|
||||||
|
params = {"UserName": user_name} if user_name else {}
|
||||||
|
return iam("ListAccessKeys", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
instance_id = inputs.get("instance_id")
|
||||||
|
if not instance_id:
|
||||||
|
raise Exception("instance_id is required")
|
||||||
|
group_ids_raw = inputs.get("group_ids")
|
||||||
|
if not group_ids_raw or not str(group_ids_raw).strip():
|
||||||
|
raise Exception("group_ids is required")
|
||||||
|
group_ids = [s.strip() for s in str(group_ids_raw).split(",") if s.strip()]
|
||||||
|
if not group_ids:
|
||||||
|
raise Exception("group_ids is required")
|
||||||
|
|
||||||
|
params = {"InstanceId": instance_id}
|
||||||
|
for i, gid in enumerate(group_ids, start=1):
|
||||||
|
params["GroupId.%d" % i] = gid
|
||||||
|
|
||||||
|
return ec2("ModifyInstanceAttribute", params, cfg, inputs)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
group_id = inputs.get("group_id")
|
||||||
|
if not group_id:
|
||||||
|
raise Exception("group_id is required")
|
||||||
|
protocol = inputs.get("protocol")
|
||||||
|
if not protocol:
|
||||||
|
raise Exception("protocol is required")
|
||||||
|
cidr = inputs.get("cidr")
|
||||||
|
if not cidr:
|
||||||
|
raise Exception("cidr is required")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"GroupId": group_id,
|
||||||
|
"IpPermissions.1.IpProtocol": protocol,
|
||||||
|
"IpPermissions.1.IpRanges.1.CidrIp": cidr,
|
||||||
|
}
|
||||||
|
from_port = inputs.get("from_port")
|
||||||
|
if from_port is not None and str(from_port).strip() != "":
|
||||||
|
params["IpPermissions.1.FromPort"] = int(from_port)
|
||||||
|
to_port = inputs.get("to_port")
|
||||||
|
if to_port is not None and str(to_port).strip() != "":
|
||||||
|
params["IpPermissions.1.ToPort"] = int(to_port)
|
||||||
|
|
||||||
|
return ec2("RevokeSecurityGroupIngress", params, cfg, inputs)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
instance_ids_raw = inputs.get("instance_ids")
|
||||||
|
if not instance_ids_raw or not str(instance_ids_raw).strip():
|
||||||
|
raise Exception("instance_ids is required")
|
||||||
|
instance_ids = [s.strip() for s in str(instance_ids_raw).split(",") if s.strip()]
|
||||||
|
if not instance_ids:
|
||||||
|
raise Exception("instance_ids is required")
|
||||||
|
|
||||||
|
force = inputs.get("force", False)
|
||||||
|
if isinstance(force, str):
|
||||||
|
force = force.strip().lower() in ("true", "1", "yes")
|
||||||
|
else:
|
||||||
|
force = bool(force)
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
for i, iid in enumerate(instance_ids, start=1):
|
||||||
|
params["InstanceId.%d" % i] = iid
|
||||||
|
if force:
|
||||||
|
params["Force"] = "true"
|
||||||
|
|
||||||
|
return ec2("StopInstances", params, cfg, inputs)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
identity = sts("GetCallerIdentity", {}, cfg)
|
||||||
|
return {"ok": True, "identity": identity}
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
import json, os, sys, hmac, hashlib, datetime
|
||||||
|
import urllib.parse, urllib.request, urllib.error
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def _cfg():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _inputs():
|
||||||
|
return json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
|
||||||
|
|
||||||
|
def _sign_key(key, date_stamp, region, service):
|
||||||
|
def _h(k, m):
|
||||||
|
return hmac.new(k, m.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
k_date = _h(("AWS4" + key).encode("utf-8"), date_stamp)
|
||||||
|
k_region = _h(k_date, region)
|
||||||
|
k_service = _h(k_region, service)
|
||||||
|
return _h(k_service, "aws4_request")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_ns(tag):
|
||||||
|
return tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
|
|
||||||
|
def _xml_to_dict(elem):
|
||||||
|
d = {}
|
||||||
|
children = list(elem)
|
||||||
|
if not children:
|
||||||
|
return (elem.text or "").strip()
|
||||||
|
for c in children:
|
||||||
|
tag = _strip_ns(c.tag)
|
||||||
|
val = _xml_to_dict(c)
|
||||||
|
if tag in d:
|
||||||
|
if not isinstance(d[tag], list):
|
||||||
|
d[tag] = [d[tag]]
|
||||||
|
d[tag].append(val)
|
||||||
|
else:
|
||||||
|
d[tag] = val
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def aws_query(service, host, region, action, version, params, cfg):
|
||||||
|
# params: dict of extra query params for this Action
|
||||||
|
body_params = {"Action": action, "Version": version}
|
||||||
|
body_params.update({k: str(v) for k, v in params.items() if v is not None})
|
||||||
|
body = urllib.parse.urlencode(sorted(body_params.items()))
|
||||||
|
|
||||||
|
access_key = str(cfg.get("access_key_id", ""))
|
||||||
|
secret_key = str(cfg.get("secret_access_key", ""))
|
||||||
|
session_token = cfg.get("session_token") or ""
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
date_stamp = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
method = "POST"
|
||||||
|
canonical_uri = "/"
|
||||||
|
canonical_querystring = ""
|
||||||
|
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
|
||||||
|
canonical_headers = "content-type:application/x-www-form-urlencoded; charset=utf-8\n" \
|
||||||
|
"host:" + host + "\n" \
|
||||||
|
"x-amz-date:" + amz_date + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date"
|
||||||
|
if session_token:
|
||||||
|
canonical_headers += "x-amz-security-token:" + session_token + "\n"
|
||||||
|
signed_headers = "content-type;host;x-amz-date;x-amz-security-token"
|
||||||
|
canonical_request = "\n".join([method, canonical_uri, canonical_querystring,
|
||||||
|
canonical_headers, signed_headers, payload_hash])
|
||||||
|
|
||||||
|
algorithm = "AWS4-HMAC-SHA256"
|
||||||
|
credential_scope = date_stamp + "/" + region + "/" + service + "/aws4_request"
|
||||||
|
string_to_sign = "\n".join([algorithm, amz_date, credential_scope,
|
||||||
|
hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()])
|
||||||
|
signing_key = _sign_key(secret_key, date_stamp, region, service)
|
||||||
|
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
authorization = (algorithm + " Credential=" + access_key + "/" + credential_scope +
|
||||||
|
", SignedHeaders=" + signed_headers + ", Signature=" + signature)
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"X-Amz-Date": amz_date,
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
if session_token:
|
||||||
|
headers["X-Amz-Security-Token"] = session_token
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://" + host + "/", data=body.encode("utf-8"), headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=60) as r:
|
||||||
|
raw = r.read()
|
||||||
|
root = ET.fromstring(raw)
|
||||||
|
return {_strip_ns(root.tag): _xml_to_dict(root)}
|
||||||
|
|
||||||
|
|
||||||
|
def _region(cfg, inputs):
|
||||||
|
return (inputs.get("region") if inputs else None) or cfg.get("region") or "us-east-1"
|
||||||
|
|
||||||
|
|
||||||
|
def ec2(action, params, cfg, inputs):
|
||||||
|
region = _region(cfg, inputs)
|
||||||
|
return aws_query("ec2", "ec2." + region + ".amazonaws.com", region, action, "2016-11-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def iam(action, params, cfg):
|
||||||
|
return aws_query("iam", "iam.amazonaws.com", "us-east-1", action, "2010-05-08", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def sts(action, params, cfg):
|
||||||
|
return aws_query("sts", "sts.amazonaws.com", "us-east-1", action, "2011-06-15", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run(fn):
|
||||||
|
try:
|
||||||
|
print(json.dumps(fn(_cfg(), _inputs())))
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(json.dumps({"error": str(e)}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(cfg, inputs):
|
||||||
|
access_key_id = inputs.get("access_key_id")
|
||||||
|
if not access_key_id:
|
||||||
|
raise Exception("access_key_id is required")
|
||||||
|
status = inputs.get("status")
|
||||||
|
if not status:
|
||||||
|
raise Exception("status is required")
|
||||||
|
if status not in ("Active", "Inactive"):
|
||||||
|
raise Exception("status must be Active or Inactive")
|
||||||
|
|
||||||
|
params = {"AccessKeyId": access_key_id, "Status": status}
|
||||||
|
user_name = inputs.get("user_name")
|
||||||
|
if user_name and str(user_name).strip():
|
||||||
|
params["UserName"] = user_name
|
||||||
|
|
||||||
|
return iam("UpdateAccessKey", params, cfg)
|
||||||
|
|
||||||
|
|
||||||
|
_run(main)
|
||||||
Reference in New Issue
Block a user