├── _config.yml ├── Cost ├── AddCustomCharges │ ├── added_charges.csv │ ├── custom_charges.csv │ ├── upload_charges_logging.log │ ├── README.md │ └── upload_custom_charges.py ├── DeleteCustomCharges │ ├── added_charges.csv │ ├── output_logging.txt │ ├── delete_custom_charges.py │ └── README.md ├── ReloadBillingDataAWS │ ├── config.txt │ ├── readme.txt │ └── ReloadBillingDataAWS.py ├── QuickBooksInvoices │ ├── logging_for_quickbooks_invoices.log │ └── README.md ├── AwsSppDiscounts │ ├── logging_for_aws_spp_discounts.log │ └── README.md ├── AwsCostAdvancedGrouping │ ├── cost_by_service.csv │ ├── README.md │ └── process_cost.py ├── FindUnmappedAccounts │ ├── package.json │ ├── README.md │ ├── FindUnmappedAccounts.json │ └── find_unmapped_accounts.js ├── ClearAccountFamilies │ ├── clear_account_families_output.log │ ├── README.md │ └── clear_account_families.py ├── AddCostAlerts │ ├── README.md │ ├── logging_for_add_cost_alerts.log │ └── add_budget_alerts.py └── AddSavedFilters │ ├── README.md │ ├── logging_for_add_saved_filter.log │ └── add_saved_filters.py ├── Onboarding ├── AddUsers │ ├── UsersCreated.csv │ ├── add_users_input.csv │ ├── README.md │ ├── logging_for_adding_users.log │ └── add_users.py ├── GetGroupAcls │ ├── permission_template_input.csv │ ├── README.md │ └── AzurePermissions.csv ├── ModifyUsers │ ├── logging_for_modify_users.log │ ├── README.md │ └── modify_users.py ├── UserGroupsGuideWithPython.pdf ├── DefaultAccountFamily │ ├── logging_for_default_account_family.log │ ├── README.md │ └── default_account_family.py ├── CredentialAWSAccounts │ ├── config.txt │ ├── readme.txt │ ├── CredentialAWSAccounts.pyproj │ └── CredentialAWSAccounts.py ├── AddAzureAccounts │ ├── ExampleOutput.log │ ├── add_azure_account.py │ └── README.md ├── CreateGroups │ ├── GroupsCreated.csv │ ├── create_groups_input.csv │ ├── README.md │ ├── create_groups.py │ └── logging_for_creating_groups.log ├── AddUsersToGroups │ ├── add_users_to_groups_input.csv │ └── README.md ├── AddGroupPermissions │ ├── group_permissions_input.csv │ └── README.md ├── UserMigration │ ├── Group.py │ ├── reset_users_and_groups.py │ ├── README.md │ └── output1.txt ├── AddAzureAccountsAndSetRoleAssignments │ └── ExampleOutput.log ├── AddAwsAccounts │ ├── ExampleOutput.log │ └── README.md └── README.md ├── CMx └── Onboarding │ └── ccgetusers │ ├── ccgetusers │ ├── __init__.py │ ├── users.py │ ├── customerid.py │ ├── generator.py │ └── command_line.py │ ├── README.md │ └── setup.py ├── media ├── 2019CClogo.png ├── cloudcheckr.png ├── CloudCheckrDeveloperCommunity.png └── 2019-cloudcheckr-logo-iconbluestroke.png ├── .gitignore ├── Offboarding ├── example_datafile_delete_accounts.csv ├── README.md └── delete_accounts.py ├── Security ├── ChangeMonitoring │ ├── output.json │ ├── README.md │ └── get_change_monitoring_events.py └── CloudTrail │ ├── output.json │ ├── README.md │ └── get_cloudtrail_alerts.py ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── LICENSE ├── Inventory ├── GetIAMUsers │ ├── output.json │ ├── README.md │ └── get_iam_users.py └── GetEC2Instances │ ├── README.md │ ├── output.json │ └── get_ec2_instances.py ├── CONTRIBUTING.md ├── aws-control-tower └── README.md ├── CloudFormationTemplate └── CF_Template_README.md ├── CODE_OF_CONDUCT.md └── README.md /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /Cost/AddCustomCharges/added_charges.csv: -------------------------------------------------------------------------------- 1 | 7 2 | 8 3 | 9 4 | 10 5 | 11 6 | -------------------------------------------------------------------------------- /Cost/DeleteCustomCharges/added_charges.csv: -------------------------------------------------------------------------------- 1 | 7 2 | 8 3 | 9 4 | 10 5 | 11 6 | -------------------------------------------------------------------------------- /Onboarding/AddUsers/UsersCreated.csv: -------------------------------------------------------------------------------- 1 | Users 2 | alec.rajeev+groupsmilan@cloudcheckr.com 3 | 4 | 5 | -------------------------------------------------------------------------------- /CMx/Onboarding/ccgetusers/ccgetusers/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Alec Rajeev' 2 | __version__ = '0.0.2' 3 | -------------------------------------------------------------------------------- /media/2019CClogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flexera-public/CloudCheckr-Developer-Community/HEAD/media/2019CClogo.png -------------------------------------------------------------------------------- /Onboarding/GetGroupAcls/permission_template_input.csv: -------------------------------------------------------------------------------- 1 | Environment,GroupName 2 | https://api.cloudcheckr.com,Permission Template -------------------------------------------------------------------------------- /Onboarding/ModifyUsers/logging_for_modify_users.log: -------------------------------------------------------------------------------- 1 | INFO:root:Modified user with email: brett.gadberry+psa@cloudcheckr.com 2 | -------------------------------------------------------------------------------- /media/cloudcheckr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flexera-public/CloudCheckr-Developer-Community/HEAD/media/cloudcheckr.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | CMx/Onboarding/ccgetusers/build/* 3 | CMx/Onboarding/ccgetusers/ccgetusers.egg* 4 | CMx/Onboarding/ccgetusers/dist/* 5 | -------------------------------------------------------------------------------- /Onboarding/UserGroupsGuideWithPython.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flexera-public/CloudCheckr-Developer-Community/HEAD/Onboarding/UserGroupsGuideWithPython.pdf -------------------------------------------------------------------------------- /media/CloudCheckrDeveloperCommunity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flexera-public/CloudCheckr-Developer-Community/HEAD/media/CloudCheckrDeveloperCommunity.png -------------------------------------------------------------------------------- /Onboarding/DefaultAccountFamily/logging_for_default_account_family.log: -------------------------------------------------------------------------------- 1 | INFO:root:Obtained account data 2 | INFO:root:Modified account family: 183698509299 (Aaron Gettings) 3 | -------------------------------------------------------------------------------- /media/2019-cloudcheckr-logo-iconbluestroke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flexera-public/CloudCheckr-Developer-Community/HEAD/media/2019-cloudcheckr-logo-iconbluestroke.png -------------------------------------------------------------------------------- /Onboarding/CredentialAWSAccounts/config.txt: -------------------------------------------------------------------------------- 1 | [config] 2 | APIKey = your_key 3 | APISecret = your_secret 4 | customerNumber = your_customer_number 5 | roleIdentifier = stack-set-name -------------------------------------------------------------------------------- /Cost/ReloadBillingDataAWS/config.txt: -------------------------------------------------------------------------------- 1 | [config] 2 | APIKey = xxxxxxx-xxxxxx-xxxx-xxxxxxxx 3 | APISecret = xxxxxxxxxxxxxxxxxxxxxxxxxxxx 4 | customerNumber = 12345667 5 | monthToReload = 2023-06-01 -------------------------------------------------------------------------------- /Onboarding/AddAzureAccounts/ExampleOutput.log: -------------------------------------------------------------------------------- 1 | {u'account_status': u'Success', u'role_account_id': u'CC-77E9F4EA28F7B9C8E29F618E98AE98B7', u'credential_status': u'Azure credentials applied.', u'cc_external_id': None, u'cc_account_id': 11} -------------------------------------------------------------------------------- /Cost/QuickBooksInvoices/logging_for_quickbooks_invoices.log: -------------------------------------------------------------------------------- 1 | INFO:root:Obtained QuickBooks Item data 2 | INFO:root:Obtained Saved Filter data: Cool Cars 3 | INFO:root:Obtained QuickBooks Customer data: Cool Cars 4 | INFO:root:Created invoice 5 | -------------------------------------------------------------------------------- /Onboarding/CreateGroups/GroupsCreated.csv: -------------------------------------------------------------------------------- 1 | GroupName,group_id 2 | Group Barcelona,d187ba0b-f4cd-477c-a345-7d90c9139bc9 3 | Group Roma,fe75fff7-8324-47ab-908e-32de9d72ae87 4 | , 5 | Group Firenze,a0f092a5-9234-4e8f-861e-bc625dbe66bf 6 | Group Milan,b0c9c0d9-c8d6-4692-bc15-aa5db4daee25 7 | -------------------------------------------------------------------------------- /Offboarding/example_datafile_delete_accounts.csv: -------------------------------------------------------------------------------- 1 | Environment,name of the account in CloudCheckr 2 | https://api.cloudcheckr.com,test46534534545 3 | https://api.cloudcheckr.com,testaccount 4 | https://api.cloudcheckr.com,test123456789012 5 | https://api.cloudcheckr.com,delete me test account 6 | -------------------------------------------------------------------------------- /Onboarding/CreateGroups/create_groups_input.csv: -------------------------------------------------------------------------------- 1 | Environment,GroupName 2 | https://api.cloudcheckr.com,Group Barcelona 3 | https://api.cloudcheckr.com,Group Roma 4 | https://api2.cloudcheckr.com,Group Medici 5 | https://api.cloudcheckr.com,Group Firenze 6 | https://api.cloudcheckr.com,Group Milan -------------------------------------------------------------------------------- /Onboarding/AddUsers/add_users_input.csv: -------------------------------------------------------------------------------- 1 | Environment,Email,Role 2 | https://api.cloudcheckr.com,alec.rajeev+groupsmilan@cloudcheckr.com,BasicUser 3 | https://api.cloudcheckr.com,alec.rajeev+groupsmilan@cloudcheckr.com,BasicUser 4 | https://api2.cloudcheckr.com,alec.rajeev+groupsmilan@cloudcheckr.com,BasicUser -------------------------------------------------------------------------------- /Security/ChangeMonitoring/output.json: -------------------------------------------------------------------------------- 1 | {'Changes': [{'ChangeType': 'Added', 'EntityType': 'Ec2Instance', 'Identifier': 'i-00000000000000000', 'ServiceType': 'Ec2', 'ChangeFound': '2018-11-12T19:14:14', 'Region': 'us-east-1', 'OldState': '[]', 'NewState': '[{"Key":"ImageId","Value":"ami-00000000000000000"}]'}]} -------------------------------------------------------------------------------- /Onboarding/AddUsersToGroups/add_users_to_groups_input.csv: -------------------------------------------------------------------------------- 1 | Environment,Email,GroupName 2 | https://api.cloudcheckr.com,alec.rajeev+groupsmilan@cloudcheckr.com,Group Firenze 3 | https://api.cloudcheckr.com,alec.rajeev+groupsmilan@cloudcheckr.com,Group Firenze2 4 | https://api2.cloudcheckr.com,alec.rajeev+groupsmilan@cloudcheckr.com,Group Firenze 5 | -------------------------------------------------------------------------------- /Cost/DeleteCustomCharges/output_logging.txt: -------------------------------------------------------------------------------- 1 | Deleted the custom charge 7 2 | {'Code': 200, 'Message': 'OK'} 3 | Deleted the custom charge 8 4 | {'Code': 200, 'Message': 'OK'} 5 | Deleted the custom charge 9 6 | {'Code': 200, 'Message': 'OK'} 7 | Deleted the custom charge 10 8 | {'Code': 200, 'Message': 'OK'} 9 | Deleted the custom charge 11 10 | {'Code': 200, 'Message': 'OK'} -------------------------------------------------------------------------------- /Cost/AddCustomCharges/custom_charges.csv: -------------------------------------------------------------------------------- 1 | Account,Amount,startDate,endDate,Description 2 | 183698509299,-0.00520548,2018-07-01,2018-07-01,Custom Charge 1 3 | 260172486890,30.001,2018-07-01,2018-07-01,Custom Charge 2 4 | 318100514071,43.221,2018-07-01,2018-07-01,Custom Charge 3 5 | 260172486890,-0.00520548,2018-07-01,2018-07-01,Custom Charge 4 6 | 318100514071,-0.00520548,2018-07-01,2018-07-01,Custom Charge 5 -------------------------------------------------------------------------------- /CMx/Onboarding/ccgetusers/README.md: -------------------------------------------------------------------------------- 1 | # ccgetusers 2 | 3 | This package is used to get a list of users from the CloudCheckr CMx API. 4 | 5 | ### Example: 6 | ``` 7 | from ccgetusers.generator import GenerateToken 8 | 9 | UsersList = ccgetusers 10 | 11 | ``` 12 | 13 | ### To call directly from the command line: 14 | ``` 15 | ccgetusers 16 | ``` 17 | 18 | ### Install module 19 | ``` 20 | python setup.py install 21 | ``` -------------------------------------------------------------------------------- /Onboarding/AddGroupPermissions/group_permissions_input.csv: -------------------------------------------------------------------------------- 1 | Environment,GroupName,AccountName 2 | https://api.cloudcheckr.com,Group Firenze,Klein 3 | https://api.cloudcheckr.com,Group Firenze,Newman 4 | https://api.cloudcheckr.com,Group Firenze2,Newman 5 | https://api2.cloudcheckr.com,Group Firenze,183698509299 6 | https://api.cloudcheckr.com,Group Firenze,AzureMav 7 | https://api.cloudcheckr.com,Group Firenze,Azure3 8 | https://api.cloudcheckr.com,Group Firenze,Azure4 9 | https://api.cloudcheckr.com,Group Firenze,All Dem Accounts 2 10 | -------------------------------------------------------------------------------- /Security/CloudTrail/output.json: -------------------------------------------------------------------------------- 1 | {'CloudTrailAlertResults': [{'Created': '2018-11-19T00:31:09', 'EventDate': '2018-11-18T23:50:47', 'EventName': 'GenerateCredentialReport', 'AccountId': '215011050627', 'IdenityArn': 'arn:aws:sts::215011050627:assumed-role/0000000-IamRole-0000000000000/0000000-IamRole-0000000000000', 'IpAddress': '00.000.000.00', 'Service': 'AmazonIAM', 'Region': 'US East (Northern Virginia)', 'ResponseType': 'Success', 'AlertName': 'Credentials report generated', 'IsThresholdResult': False, 'IpRisk': False, 'AlertStatus': 'Enabled', 'RequestParams': ''}]} 2 | -------------------------------------------------------------------------------- /Cost/ReloadBillingDataAWS/readme.txt: -------------------------------------------------------------------------------- 1 | reloadbillingdataaws.py 2 | Author: Kurt Jordan 3 | 4 | This script is designed to recognize each payer account in your environment and reprocess the month designated in the config file. 5 | requirements: 6 | 7 | edit the config.txt file to include the following: 8 | 9 | APIKey - use the following to create the api key and secret. https://success.cloudcheckr.com/article/93urirlmng-cloudcheckr-cmx-api 10 | APISecret - permissions needed: [CloudCheckr API Access][Full Administration] 11 | customerNumber - can be obtained in the URL of CloudCheckr behind https://app-us.cloudcheckr.com/customers/xxxxxx 12 | monthToReload = 2023-06-01 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | labels: 5 | 6 | --- 7 | 8 | **Is your feature request related to a problem? Please describe.** 9 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 10 | 11 | **Describe the solution you'd like** 12 | A clear and concise description of what you want to happen. 13 | 14 | **Describe alternatives you've considered** 15 | A clear and concise description of any alternative solutions or features you've considered. 16 | 17 | **Additional context** 18 | Add any other context or screenshots about the feature request here. 19 | -------------------------------------------------------------------------------- /CMx/Onboarding/ccgetusers/ccgetusers/users.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | import re 4 | import logging 5 | import requests 6 | 7 | log = logging.getLogger(__name__) 8 | 9 | 10 | class Users: 11 | def __init__(self, cc_endpoint, token, customer_id): 12 | """ 13 | Gets the list of users 14 | """ 15 | api_url = cc_endpoint + "/auth/v1/customers/" + customer_id + "/users" 16 | authorization_value = "Bearer " + token 17 | 18 | response = requests.get(api_url, headers={"Authorization": authorization_value}) 19 | 20 | self._users = response.json() 21 | 22 | @property 23 | def users(self): 24 | return self._users 25 | -------------------------------------------------------------------------------- /Cost/AwsSppDiscounts/logging_for_aws_spp_discounts.log: -------------------------------------------------------------------------------- 1 | INFO:root:Obtained SPP account data 2 | INFO:root:Obtained custom billing charge data 3 | INFO:root:Modified custom billing charge: Support Discount 4 | INFO:root:Modified custom billing charge: Net New Account 5 | INFO:root:Modified custom billing charge: Internal Discount 6 | INFO:root:Modified custom billing charge: Shareshift1 Discount 7 | INFO:root:Modified custom billing charge: Shareshift2 Discount 8 | INFO:root:Modified custom billing charge: Shareshift3 Discount 9 | INFO:root:Modified custom billing charge: Shareshift4 Discount 10 | INFO:root:Modified custom billing charge: Base Discount 11 | INFO:root:Modified custom billing charge: Tech Discount 12 | -------------------------------------------------------------------------------- /CMx/Onboarding/ccgetusers/ccgetusers/customerid.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | import re 4 | import logging 5 | import requests 6 | 7 | log = logging.getLogger(__name__) 8 | 9 | 10 | class CustomerId: 11 | def __init__(self, cc_endpoint, token): 12 | """ 13 | Gets the Customer id 14 | """ 15 | api_url = cc_endpoint + "/auth/v1/token/info" 16 | authorization_value = "Bearer " + token 17 | 18 | response = requests.get(api_url, headers={"Authorization": authorization_value}) 19 | 20 | if "customerId" in response.json(): 21 | self._customer_id = response.json()["customerId"] 22 | 23 | @property 24 | def customer_id(self): 25 | return self._customer_id 26 | -------------------------------------------------------------------------------- /Onboarding/UserMigration/Group.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Group(object): 4 | 5 | 6 | def __init__(self, id1, id2, name): 7 | self.id1 = id1 8 | self.id2 = id2 9 | self.name = name 10 | self.users = None 11 | 12 | def add_users(self, user_list): 13 | self.users = user_list 14 | 15 | def check_user(self, user_email): 16 | if (self.users is None): 17 | return False 18 | if (np.size(self.users) == 0): 19 | return False 20 | for i in np.arange(0, np.size(self.users)): 21 | if (user_email == self.users[i]): 22 | return True 23 | return False 24 | 25 | def __str__(self): 26 | return str(self.name) + "is " + str(self.id1) + " : " + str(self.id2) -------------------------------------------------------------------------------- /Cost/AwsCostAdvancedGrouping/cost_by_service.csv: -------------------------------------------------------------------------------- 1 | GroupValue,Dec2020 2 | Cost Explorer,10.00 3 | Lambda,10.00 4 | VPC,10.00 5 | Elastic Load Balancing,10.00 6 | Database Migration Service,10.00 7 | SNS,10.00 8 | SimpleDB,10.00 9 | CloudWatch,10.00 10 | RDS,10.00 11 | Elastic File System,10.00 12 | Data Pipeline,10.00 13 | Secrets Manager,10.00 14 | Directory Service,10.00 15 | IoT,10.00 16 | ElastiCache,10.00 17 | Web Application Firewall,10.00 18 | DynamoDB,10.00 19 | Route 53,10.00 20 | S3,10.00 21 | CloudTrail,10.00 22 | Guard Duty,10.00 23 | EC2,10.00 24 | SQS,10.00 25 | Kinesis,10.00 26 | EC2 Container Registry,10.00 27 | Glacier,10.00 28 | Compute Savings Plans,10.00 29 | Redshift,10.00 30 | Elasticsearch Service,10.00 31 | SWF,10.00 32 | Config,10.00 33 | Key Management Service,10.00 34 | WorkSpaces,10.00 35 | US Sales Tax,10.00 36 | Support Business,10.00 37 | CloudFront,10.00 38 | -------------------------------------------------------------------------------- /CMx/Onboarding/ccgetusers/ccgetusers/generator.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | import re 4 | import logging 5 | import requests 6 | 7 | log = logging.getLogger(__name__) 8 | 9 | 10 | class GenerateToken: 11 | def __init__(self, cc_endpoint, client_id, client_secret): 12 | """ 13 | Uses OAuth 2.0 to get the Bearer Token 14 | """ 15 | api_url = cc_endpoint + "/auth/connect/token" 16 | 17 | client = {'grant_type': 'client_credentials', 18 | 'client_id': client_id, 19 | 'client_secret': client_secret, 20 | 'scope': 'api' 21 | } 22 | 23 | response = requests.post(api_url, data=client) 24 | 25 | if "access_token" in response.json(): 26 | self._token = response.json()["access_token"] 27 | 28 | @property 29 | def token(self): 30 | return self._token 31 | -------------------------------------------------------------------------------- /Onboarding/AddAzureAccountsAndSetRoleAssignments/ExampleOutput.log: -------------------------------------------------------------------------------- 1 | {'properties': {'roleDefinitionId': '/subscriptions/8a0cc1ed-43f0-4e03-8358-56eeb88571a6/providers/Microsoft.Authorization/roleDefinitions/602286d7-7f14-4889-a435-3e47d00c794d', 'principalId': '14c5a160-e941-46b6-8df8-1d59a8e31ea2', 'scope': '/subscriptions/4449fed6-cfc1-4bec-8c92-e1c67c72c824', 'createdOn': '2020-06-18T03:15:37.0801824Z', 'updatedOn': '2020-06-18T03:15:37.0801824Z', 'createdBy': None, 'updatedBy': '6357a2e7-166b-414e-bad5-337e7e8cea10'}, 'id': '/subscriptions/8a0cc1ed-43f0-4e03-8358-56eeb88571a6/providers/Microsoft.Authorization/roleAssignments/faa2c9fa-b111-11ea-b5f6-34e12d24556e', 'type': 'Microsoft.Authorization/roleAssignments', 'name': 'faa2c9fa-b111-11ea-b5f6-34e12d24556e'} 2 | {'account_status': 'Success', 'cc_account_id': 12, 'credential_status': 'Azure credentials applied.', 'role_account_id': 'CC-804E7E6F20C3294868C86EC6568F4394', 'cc_external_id': None} -------------------------------------------------------------------------------- /Cost/FindUnmappedAccounts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "find_unmapped_accounts", 3 | "version": "1.0.0", 4 | "description": "validate account families in CloudCheckr", 5 | "main": "find_unmapped_accounts.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Michael Atkinson", 10 | "license": "UNLICENSED", 11 | "dependencies": { 12 | "aws-sdk": "^2.6.1", 13 | "request": "^2.74.0" 14 | }, 15 | "devDependencies": {}, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/CloudCheckr/Developer-Community.git" 19 | }, 20 | "keywords": [ 21 | "cloudcheckr", 22 | "account", 23 | "families" 24 | ], 25 | "bugs": { 26 | "url": "https://github.com/CloudCheckr/Developer-Community/issues" 27 | }, 28 | "homepage": "https://github.com/CloudCheckr/Developer-Community/tree/master/Cost/FindUnmappedAccounts#readme" 29 | } 30 | -------------------------------------------------------------------------------- /CMx/Onboarding/ccgetusers/ccgetusers/command_line.py: -------------------------------------------------------------------------------- 1 | from ccgetusers.generator import GenerateToken 2 | from ccgetusers.customerid import CustomerId 3 | from ccgetusers.users import Users 4 | import sys 5 | 6 | 7 | def main(): 8 | if len(sys.argv) < 4: 9 | print('Must provide CloudCheckr CMx auth endpoint, client id and access key') 10 | print('ccgetusers ') 11 | sys.exit(-1) 12 | else: 13 | cc_endpoint = sys.argv[1] 14 | client_id = sys.argv[2] 15 | client_secret = sys.argv[3] 16 | token = GenerateToken(cc_endpoint=cc_endpoint, client_id=client_id, client_secret=client_secret) 17 | token = token.token 18 | customer_id = CustomerId(cc_endpoint=cc_endpoint, token=token) 19 | customer_id = customer_id.customer_id 20 | users = Users(cc_endpoint=cc_endpoint, token=token, customer_id=customer_id) 21 | return users.users 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: 5 | 6 | --- 7 | 8 | **Describe the bug** 9 | A clear and concise description of what the bug is. 10 | 11 | **To Reproduce** 12 | Steps to reproduce the behavior: 13 | 1. Go to '...' 14 | 2. Click on '....' 15 | 3. Scroll down to '....' 16 | 4. See error 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | **Desktop (please complete the following information):** 25 | - OS: [e.g. iOS] 26 | - Browser [e.g. chrome, safari] 27 | - Version [e.g. 22] 28 | 29 | **Smartphone (please complete the following information):** 30 | - Device: [e.g. iPhone6] 31 | - OS: [e.g. iOS8.1] 32 | - Browser [e.g. stock browser, safari] 33 | - Version [e.g. 22] 34 | 35 | **Additional context** 36 | Add any other context about the problem here. 37 | -------------------------------------------------------------------------------- /CMx/Onboarding/ccgetusers/setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | install_requires = [ 4 | "requests" 5 | ] 6 | 7 | with open("README.md", "r") as fh: 8 | long_description = fh.read() 9 | 10 | setuptools.setup( 11 | name="ccgetusers", 12 | version="0.0.1", 13 | author="Alec Rajeev", 14 | author_email="alecinthecloud@gmail.com", 15 | description="Package for getting a list of users from cloudcheckr", 16 | long_description=long_description, 17 | long_description_content_type="text/markdown", 18 | url="https://github.com/cloudcheckr/Developer-Community/", 19 | packages=setuptools.find_packages(), 20 | install_requires=install_requires, 21 | classifiers=[ 22 | "Programming Language :: Python :: 3", 23 | "License :: OSI Approved :: MIT License", 24 | "Operating System :: OS Independent", 25 | ], 26 | python_requires='>=3.6.5', 27 | entry_points={'console_scripts': ['ccgetusers=ccgetusers.command_line:main']}, 28 | ) 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CloudCheckr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Cost/ClearAccountFamilies/clear_account_families_output.log: -------------------------------------------------------------------------------- 1 | Skipping the deletion of the account family Payer Account Family 2 | Successfully deleted the account family 103237659442 3 | {'Code': 200, 'Message': 'OK'} 4 | Successfully deleted the account family 121212121212 5 | {'Code': 200, 'Message': 'OK'} 6 | Successfully deleted the account family 121234345625 7 | {'Code': 200, 'Message': 'OK'} 8 | Successfully deleted the account family 123456456454 9 | {'Code': 200, 'Message': 'OK'} 10 | Successfully deleted the account family 183698509299 11 | {'Code': 200, 'Message': 'OK'} 12 | Successfully deleted the account family 245990094719 13 | {'Code': 200, 'Message': 'OK'} 14 | Successfully deleted the account family 260172486890 15 | {'Code': 200, 'Message': 'OK'} 16 | Successfully deleted the account family 318100514071 17 | {'Code': 200, 'Message': 'OK'} 18 | Successfully deleted the account family 443094636793 19 | {'Code': 200, 'Message': 'OK'} 20 | Successfully deleted the account family 557949322966 21 | {'Code': 200, 'Message': 'OK'} 22 | Successfully deleted the account family 614053097691 23 | {'Code': 200, 'Message': 'OK'} 24 | Finished deleting account families 25 | -------------------------------------------------------------------------------- /Security/ChangeMonitoring/README.md: -------------------------------------------------------------------------------- 1 | # Get Changes with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html, https://pandas.pydata.org/pandas-docs/stable/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the name of the account that you would like to get the changes of on line 53. 12 | 7. Run python add_saved_filters.py 13 | 14 | --- 15 | 16 | ## How the program works 17 | 18 | It uses the [get_changes](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-api-reference-guide/#get_changes) API call to export all of the changes found by CloudCheckr's Change Monitoring. 19 | 20 | You can view Change Monitoring through the UI with Security -> Change Monitoring. 21 | 22 | --- 23 | 24 | ## Assumptions 25 | 26 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 51 if required. -------------------------------------------------------------------------------- /Onboarding/AddAwsAccounts/ExampleOutput.log: -------------------------------------------------------------------------------- 1 | Successfully created the account AlecAccount with external_id CC-00000000000000000000000000000000 2 | {'account_status': 'Success', 'cc_account_id': 44, 'credential_status': 'No credentials given. Can use the following role_account_id and role_external_id to create cross-account role within AWS.', 'role_account_id': '352813966189', 'cc_external_id': 'CC-00000000000000000000000000000000'} 3 | {'StackId': 'arn:aws:cloudformation:us-east-1:020403522555:stack/cc-iam-stack-api/0117a3a0-eb69-11e8-80fa-50fae98974fd', 'ResponseMetadata': {'RequestId': '67d907a9-eb69-11e8-8e73-673b8c90e28b', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '67d907a9-eb69-11e8-8e73-673b8c90e28b', 'content-type': 'text/xml', 'content-length': '386', 'date': 'Sun, 18 Nov 2018 19:37:37 GMT'}, 'RetryAttempts': 0}} 4 | Built in wait of 30 seconds to allow stack to be created 5 | Created a RoleArn 6 | Created arn:aws:iam::020403522555:role/cc-iam-stack-api-IamRole-1MGTKVEC1888L 7 | Found role. Waiting 10 seconds before adding to CloudCheckr. 8 | Successfully added the role arn:aws:iam::020403522555:role/cc-iam-stack-api-IamRole-1MGTKVEC1888L to the CloudCheckr Account AlecAccount 9 | {'Code': 200, 'Message': 'OK'} -------------------------------------------------------------------------------- /Onboarding/ModifyUsers/README.md: -------------------------------------------------------------------------------- 1 | # Modify Users with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 1. Install python 3. https://www.python.org/downloads/ 8 | 2. Install requests and logging libraries with pip 9 | 3. Log into CloudCheckr and create an Admin API access key at Admin Functions >> Admin API Key, https://app.cloudcheckr.com/Project/GlobalApiCredentials 10 | 4. Run python modify_users.py 11 | 12 | --- 13 | 14 | ## How the program works 15 | 16 | Uses [get_users_v2](https://success.cloudcheckr.com/article/kr5glkrmon-admin-api-reference-guide#get_users_v2) API call to get user data for edit_user API call. 17 | 18 | Uses [edit_user](https://success.cloudcheckr.com/article/kr5glkrmon-admin-api-reference-guide#edit_user) API call to modify users as per the criteria and desired result. 19 | 20 | The criteria is set at line 30. 21 | 22 | The desired result is set at line 44. 23 | 24 | The program is set to modify users with user role, PartnerSysAdmin, to user role, Administrator. 25 | 26 | You can view CloudCheckr Users through the UI at Settings >> Users. 27 | 28 | --- 29 | 30 | ## Assumptions 31 | 32 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 71 if required. 33 | -------------------------------------------------------------------------------- /Inventory/GetIAMUsers/output.json: -------------------------------------------------------------------------------- 1 | [{'UserName': 'User1', 'LastModified': '2018-02-02T20:36:19Z', 'LastUsed': None, 'HasMfa': False, 'Groups': [], 'AccessKeys': [{'AccessKeyId': 'AAAAAAAAAAAAAAAAAAAA', 'Status': 'Active', 'CreateDate': '2018-10-02T14:14:00Z'}], 'MfaDevices': [], 'Policies': [{'PolicyName': 'IAMUserChangePassword', 'PolicyId': 1663244}], 'UserCredential': {'Id': 943833, 'UserName': '00000', 'Arn': 'arn:aws:iam::215011050627:user/00000', 'UserCreationTime': '2018-02-02T20:36:19', 'PasswordEnabled': True, 'PasswordLastUsed': None, 'PasswordLastChanged': '2018-02-02T20:36:21', 'PasswordNextRotation': None, 'IsMfaActive': False, 'IsAccessKey1Active': True, 'AccessKey1LastRotated': '2018-10-02T14:14:00', 'AccessKey1LastUsedDate': '2018-11-18T12:22:00', 'AccessKey1LastUsedRegion': 'ap-northeast-1', 'AccessKey1LastUsedService': 'cloudwatch', 'IsAccessKey2Active': False, 'AccessKey2LastRotated': None, 'AccessKey2LastUsedDate': None, 'AccessKey2LastUsedRegion': 'N/A', 'AccessKey2LastUsedService': 'N/A', 'IsCert1Active': False, 'Cert1LastRotated': None, 'IsCert2Active': False, 'Cert2LastRotated': None, 'AccountName': None, 'Title': None, 'Identifier': '00000000000000000000000000000000', 'AccessKey1CreatedDate': '2018-10-02T14:14:00Z', 'AccessKey2CreatedDate': None}, 'AccountName': None}] 2 | 3 | -------------------------------------------------------------------------------- /Cost/AwsCostAdvancedGrouping/README.md: -------------------------------------------------------------------------------- 1 | **Get Advanced Grouping Data with the CloudCheckr API** 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy, and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the CloudCheckr Account name of the payer account to line 54 in the variable cc_account_name. 12 | 5. Run python process_cost.py 13 | 14 | --- 15 | 16 | ## How the program works 17 | 18 | It uses the [get_detailed_billing_v2](https://success.cloudcheckr.com/article/7sskuffbg6-api-reference-guide#list_results_from_an_advanced_grouping_saved_filter) API call pull results from a specified saved filter 19 | 20 | 21 | You can create a saved filter by following the instructions on [advanced-grouping-report](https://success.cloudcheckr.com/article/5s11l0k4fo-advanced-grouping-report). 22 | 23 | 24 | --- 25 | 26 | ## Assumptions 27 | 28 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 51 if required. -------------------------------------------------------------------------------- /Inventory/GetIAMUsers/README.md: -------------------------------------------------------------------------------- 1 | # Get IAM Users with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html, https://pandas.pydata.org/pandas-docs/stable/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the name of the account that you would like to get the changes of on line 87. You can use an All Accounts MAV to pull of the IAM Users in a MAV. 12 | 7. Run python get_iam_users.py 13 | 14 | --- 15 | 16 | ## How the program works 17 | 18 | It uses the [get_resources_iam_users](https://support.cloudcheckr.com/cloudcheckr-api-userguide/api-reference-guide-inventory/#get_resources_iam_users) API call to export all of the IAM Users in an account. It will loop through all tokens or pages of the call. 19 | 20 | You can view IAM User Inventory through the UI with Inventory -> IAM -> List of Users. 21 | 22 | --- 23 | 24 | ## Assumptions 25 | 26 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 84 if required. -------------------------------------------------------------------------------- /Security/CloudTrail/README.md: -------------------------------------------------------------------------------- 1 | # Get CloudTrail Alerts with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html, https://pandas.pydata.org/pandas-docs/stable/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the name of the account that you would like to get the changes of on line 51. 12 | 7. Run python add_saved_filters.py 13 | 14 | --- 15 | 16 | ## How the program works 17 | 18 | It uses the [get_cloudtrail_alert_results_v2](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-api-reference-guide/#get_cloudtrail_alert_results_v2) API call to export all of the cloud trail alerts found by CloudCheckr. You can filter on a specific alert with the alert_name parameter. 19 | 20 | You can view Change Monitoring through the UI with Security -> Alerts -> CloudTrail -> Results. 21 | 22 | --- 23 | 24 | ## Assumptions 25 | 26 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 51 if required. -------------------------------------------------------------------------------- /Inventory/GetEC2Instances/README.md: -------------------------------------------------------------------------------- 1 | # Get EC2 Instances with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html, https://pandas.pydata.org/pandas-docs/stable/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the name of the account that you would like to get the changes of on line 87. You can use an All Accounts MAV to pull of the instances in a MAV. 12 | 7. Run python get_ec2_instances.py 13 | 14 | --- 15 | 16 | ## How the program works 17 | 18 | It uses the [get_resources_ec2_details_V4](https://support.cloudcheckr.com/cloudcheckr-api-userguide/api-reference-guide-inventory/#get_resources_ec2_details_V3) API call to export all of the EC2 Instances in an account. It will loop through all tokens or pages of the call. 19 | 20 | You can view EC2 Inventory through the UI with Inventory -> EC2 -> List of EC2 Instances. 21 | 22 | --- 23 | 24 | ## Assumptions 25 | 26 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 84 if required. -------------------------------------------------------------------------------- /Offboarding/README.md: -------------------------------------------------------------------------------- 1 | **Offboard Accounts with Python and CloudCheckr API** 2 | 3 | 1) This python script is used to delete accounts based on the list of accounts provided in a csv file named 'accounts_list'. Please see example datafile for formatting (example_datafile_delete_accounts.csv). 4 | 2) For the data file, please define 2 columns: 5 | - Column 1: the API URI for your region in CloudCheckr 6 | - Valid regions: 7 | - https://api.cloudcheckr.com 8 | - https://eu.cloudcheckr.com 9 | - https://au.cloudcheckr.com 10 | - https://gov.cloudcheckr.com 11 | - Column 2: the corresponding account name of the account you wish to be deleted (as it appears in the CloudCheckr landing page) 12 | Note: The first row is for column names 13 | 3) To call this script, use the following: python3 delete_accounts.py 14 | 4) Please ensure that this file is in the same folder/directory as the data file. 15 | 5) Once the script has completed, please check the log file for errors to validate that all your anticipated changes were successfully made by the API. If you do see errors and need assistance, CloudCheckr Support may be able to provide further assistance if an Error Identity code is found in the logs. Please provide us the log file so that we may look into the error. 16 | -------------------------------------------------------------------------------- /Onboarding/CredentialAWSAccounts/readme.txt: -------------------------------------------------------------------------------- 1 | CredentialAWSAccounts.py 2 | Author: Kurt Jordan 3 | 4 | 5 | The purpose of this script is to programatically check for all accounts which are either in a "failed" or "not credentialed" state and credential it after you have created a stack set. 6 | 7 | The stack set should create an IAM role for each of your sub accounts and provide an ARN we will use for credentialing. 8 | 9 | 10 | requirements: 11 | edit the config.txt file to include the following: 12 | APIKey - use the following to create the api key and secret. https://success.cloudcheckr.com/article/93urirlmng-cloudcheckr-cmx-api 13 | APISecret - permissions needed should need at minimum "Account Management" 14 | customerNumber - can be obtained in the URL of CloudCheckr behind https://app-us.cloudcheckr.com/customers/xxxxxx 15 | roleIdentifier - 16 | this will be the last part of the arn following role/ 17 | for example arn:aws:iam::123456789:role/cc-role-test-1 you would enter cc-role-test-1 as the roleIdentifier 18 | if each account is being created with random trailing digits you will need to edit the template used to deploy the stack set. 19 | Do this by adding "RoleName" : cc-iam-role to the cloudformation template. This removes the random string of characters appended normally at the end. 20 | https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html 21 | 22 | 23 | -------------------------------------------------------------------------------- /Onboarding/DefaultAccountFamily/README.md: -------------------------------------------------------------------------------- 1 | # Default Account Family with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 1. Install python 3, https://www.python.org/downloads/ 8 | 2. Install requests and logging libraries with pip 9 | 3. Log into CloudCheckr and create an Admin API access key at Admin Functions >> Admin API Key, https://app.cloudcheckr.com/Project/GlobalApiCredentials 10 | 4. Run python default_account_family.py 11 | 12 | --- 13 | 14 | ## How the program works 15 | 16 | Uses [get_account_family_v2](https://success.cloudcheckr.com/article/kr5glkrmon-admin-api-reference-guide#get_account_family_v2) API call to get account data for modify_account_family API call. 17 | 18 | Uses [modify_account_family](https://success.cloudcheckr.com/article/kr5glkrmon-admin-api-reference-guide#modify_account_family) API call to add all unmapped accounts to default account family. 19 | 20 | The payer project id is the CloudCheckr project id of the AWS Payer account. 21 | 22 | The default account familty is the name of the account family that all unmapped accounts will be added to. 23 | 24 | You can view Account Families through the UI at Cost >> AWS Partner Tools >> Configure >> Account Families. 25 | 26 | --- 27 | 28 | ## Assumptions 29 | 30 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 97 if required. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Contributing code 2 | 3 | The CloudCheckr Developer Community has a [Code of Conduct](https://github.com/CloudCheckr/Developer-Community/blob/master/CODE_OF_CONDUCT.md), you can expect to be treated with respect at all times when interacting with this project. 4 | 5 | Contributing Code 6 | ----------------- 7 | A good pull request: 8 | 9 | - Is clear. 10 | - Follows the existing style of the code base (PEP-8). 11 | - Has comments included as needed. 12 | 13 | - Example output is included to verify how the script runs successfully. 14 | - If it adds/changes a public API, it must also include documentation 15 | for those changes. 16 | 17 | - If it is a feature, name the branch feature/branch-name. 18 | - If it is a bug, name the branch bug/branch-name. 19 | 20 | Reporting An Issue/Feature 21 | -------------------------- 22 | First, check to see if there's an existing issue/pull request for the 23 | [bug](.github/ISSUE_TEMPLATE/bug_report.md)/[feature](.github/ISSUE_TEMPLATE/feature_request.md). All issues are at 24 | https://github.com/CloudCheckr/Developer-Community/issues and pull reqs are at 25 | https://github.com/CloudCheckr/Developer-Community/pulls. 26 | 27 | If there isn't an existing issue there, please file an issue. The 28 | ideal report includes: 29 | 30 | - A description of the problem/suggestion. 31 | - How to recreate the bug. 32 | 33 | - If possible, create a pull request with a (failing) test case 34 | demonstrating what's wrong. This makes the process for fixing bugs 35 | quicker & gets issues resolved sooner. 36 | -------------------------------------------------------------------------------- /aws-control-tower/README.md: -------------------------------------------------------------------------------- 1 | # AWS Control Tower Integration 2 | 3 | 4 | ## What is this? 5 | 6 | This is the folder that contains the CloudCheckr CMx AWS Control Tower Integration. AWS Control Tower is a Service that allows customers to more easily govern and secure a multi-account AWS environment. This CloudCheckr CMx AWS Control Tower integration allows customers to more easily add new AWS accounts to CloudCheckr. 7 | 8 | ## Why are we doing this? 9 | 10 | The goal is to provide a way for CloudCheckr customers to use their existing AWS Control Tower set up to automatically add new accounts to CloudCheckr CMx. Any new account that gets added will recieve a daily assement of CloudCheckr's 500 best practice checks identifying ways to improve cost and security. 11 | 12 | ## How do I use this? 13 | 14 | See our [implementation guide](https://d1.awsstatic.com/Marketplace/solutions-center/downloads/AWS-CloudCheckr-Implementation-Guide.pdf) for full details. 15 | 16 | 17 | ## CloudFormation Templates 18 | 19 | Here are the two CloudFormation templates in the templates folder. 20 | 21 | * `cloudcheckr-controltower-integration.template.yaml` is the template to deploy the integration. It will require the s3 bucket and file with the lambda zip artifact. 22 | * `iam-permissions-control-tower-integration.json` is the template to create the cross-account IAM role. This template takes the IAM role name as an input. 23 | 24 | ## Contributing 25 | 26 | This is an open source project and welcomes contributions. 27 | 28 | 29 | See our [Contributing Guide](../CONTRIBUTING.md) for more details. -------------------------------------------------------------------------------- /Cost/AddCustomCharges/upload_charges_logging.log: -------------------------------------------------------------------------------- 1 | INFO:root:[('183698509299', '-0.00520548', '2018-07-01', '2018-07-01', 'Custom Charge 1') 2 | ('260172486890', '30.001', '2018-07-01', '2018-07-01', 'Custom Charge 2') 3 | ('318100514071', '43.221', '2018-07-01', '2018-07-01', 'Custom Charge 3') 4 | ('260172486890', '-0.00520548', '2018-07-01', '2018-07-01', 'Custom Charge 4') 5 | ('318100514071', '-0.00520548', '2018-07-01', '2018-07-01', 'Custom Charge 5')] 6 | INFO:root: 7 | 8 | INFO:root:Added the custom charge Custom Charge 1 with the amount -0.00520548 for the AWS Account 183698509299 with a start date of 2018-07-01 9 | INFO:root:{'Id': 7, 'Code': 200, 'Message': 'OK'} 10 | INFO:root: 11 | 12 | INFO:root:Added the custom charge Custom Charge 2 with the amount 30.001 for the AWS Account 260172486890 with a start date of 2018-07-01 13 | INFO:root:{'Id': 8, 'Code': 200, 'Message': 'OK'} 14 | INFO:root: 15 | 16 | INFO:root:Added the custom charge Custom Charge 3 with the amount 43.221 for the AWS Account 318100514071 with a start date of 2018-07-01 17 | INFO:root:{'Id': 9, 'Code': 200, 'Message': 'OK'} 18 | INFO:root: 19 | 20 | INFO:root:Added the custom charge Custom Charge 4 with the amount -0.00520548 for the AWS Account 260172486890 with a start date of 2018-07-01 21 | INFO:root:{'Id': 10, 'Code': 200, 'Message': 'OK'} 22 | INFO:root: 23 | 24 | INFO:root:Added the custom charge Custom Charge 5 with the amount -0.00520548 for the AWS Account 318100514071 with a start date of 2018-07-01 25 | INFO:root:{'Id': 11, 'Code': 200, 'Message': 'OK'} 26 | INFO:root: 27 | 28 | INFO:root:Saved custom charge id's added to added_charges.csv 29 | -------------------------------------------------------------------------------- /Onboarding/CredentialAWSAccounts/CredentialAWSAccounts.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 111812c2-870d-430d-a622-afcfd513f22b 6 | . 7 | CredentialAWSAccounts.py 8 | 9 | 10 | . 11 | . 12 | CredentialAWSAccounts 13 | CredentialAWSAccounts 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Cost/AddCostAlerts/README.md: -------------------------------------------------------------------------------- 1 | # Add Budget Alerts with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html, https://pandas.pydata.org/pandas-docs/stable/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the emails that you would like the alert to go to on line 111. 12 | 5. Enter the budget alert name on line 114. 13 | 6. Enter the budget amount on line 117. 14 | 7. Enter the budget period on line 123. It will default to monthly. 15 | 8. Run python add_budget_alerts.py 16 | 17 | --- 18 | 19 | ## How the program works 20 | 21 | It uses the [add_cost_alert](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-api-reference-guide/#add_cost_alert) Admin API call to add a budget alert to every account. 22 | 23 | This API call will only work with AWS and Non-MAV accounts, so it uses the [get_accounts_v4](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_accounts_v4) to get all of the accounts. Then uses the [get_account](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_account) API call to check the type. 24 | 25 | 26 | You can view the budget alerts by going to Cost -> Alerts -> Manager. 27 | 28 | --- 29 | 30 | ## Assumptions 31 | 32 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 108 if required. 33 | 2. Every account gets the same budget amount. -------------------------------------------------------------------------------- /Cost/DeleteCustomCharges/delete_custom_charges.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import json 3 | import requests 4 | import sys 5 | 6 | # python delete_custom_charges.py 0000000000000000000000000000000000000000000000000000000000000000 7 | 8 | 9 | def load_custom_charges(custom_charges_file): 10 | 11 | custom_charges_dtype = [("Id", "U36")] 12 | 13 | custom_charges = np.loadtxt(custom_charges_file, dtype="U36", delimiter=",") 14 | # print(custom_charges) 15 | 16 | return custom_charges 17 | 18 | 19 | def delete_custom_fixed_charge(env, admin_api_key,custom_charge_id, payer_account_name): 20 | 21 | api_url = env + "api/billing.json/delete_custom_billing_charge" 22 | 23 | chargeData = json.dumps({"Id": custom_charge_id, "use_account": payer_account_name}) 24 | 25 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = chargeData) 26 | 27 | print("Deleted the custom charge " + str(custom_charge_id)) 28 | print(r7.json()) 29 | 30 | def cycle_custom_charges(env, admin_api_key, custom_charges, payer_account_name): 31 | 32 | 33 | charge_ids = np.array([]) 34 | 35 | for i in np.arange(0, np.shape(custom_charges)[0]): 36 | charge_id = delete_custom_fixed_charge(env, admin_api_key,custom_charges[i], payer_account_name) 37 | 38 | 39 | def main(): 40 | try: 41 | admin_api_key = str(sys.argv[1]) 42 | except IndexError: 43 | print("Must admin_api_key") 44 | return 45 | 46 | env = "https://api.cloudcheckr.com/" 47 | 48 | payer_account_name = "Payer Master Account" 49 | 50 | custom_charges_file = "added_charges.csv" 51 | 52 | custom_charges = load_custom_charges(custom_charges_file) 53 | 54 | charge_ids = cycle_custom_charges(env, admin_api_key, custom_charges, payer_account_name) 55 | 56 | 57 | 58 | if __name__ == "__main__": 59 | main() -------------------------------------------------------------------------------- /Cost/AddSavedFilters/README.md: -------------------------------------------------------------------------------- 1 | # Add Saved Filters with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html, https://pandas.pydata.org/pandas-docs/stable/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the emails that you would like the alert to go to on line 113. 12 | 5. Enter the group bys on line 116. 13 | 6. Enter the cost type on line 119. 14 | 7. Run python add_saved_filters.py 15 | 16 | --- 17 | 18 | ## How the program works 19 | 20 | It uses the [create_detailed_billing_grouped_filter_v2](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-api-reference-guide/#create_detailed_billing_grouped_filter_v2) API call to add a saved filter to every AWS Account. 21 | 22 | This API call will work with both AWS and Azure accounts, but the input parameters are slightly different. This script is optimized for the AWS version and uses the [get_accounts_v4](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_accounts_v4) to get all of the accounts. Then uses the [get_account](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_account) API call to check the type. 23 | 24 | 25 | You can view the saved filter by going to Cost -> AWS Billing -> Custom Reporting -> Advanced Grouping. 26 | 27 | --- 28 | 29 | ## Assumptions 30 | 31 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 108 if required. 32 | 2. Every account gets the same saved filter. -------------------------------------------------------------------------------- /Onboarding/CreateGroups/README.md: -------------------------------------------------------------------------------- 1 | # Use CloudCheckr's API to Create Groups 2 | 3 | The purpose of this script is to create groups with the CloudCheckr API. 4 | 5 | --- 6 | 7 | ## Steps to Setup Input File 8 | 9 | 1. Navigate to the CreateGroups folder. 10 | 2. In the first column write the environment such as https://api.cloudcheckr.com 11 | 3. In the second column unique name of a group that you wish to create. 12 | 4. Repeat the above for as many groups as you wish to create. 13 | 14 | --- 15 | 16 | ## Steps to Run Create Groups Program 17 | 18 | 1. Run the python program create_groups.py. 19 | 2. You must put the admin api key as a command line input. An example is below. 20 | 3. python create_groups.py 0000000000000000000000000000000000000000000000000000000000000000 21 | 4. If this runs as expected, it will ouput a groups created csv file with all the groups successfully created. 22 | 23 | --- 24 | 25 | ## How this program works. 26 | 27 | This program will read the names of groups from the group input template csv file using pandas [read_csv](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html). These group names must be unique because of this. It will use a get request with [get_groups_v2](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_groups_v2) to check for duplicate group names and warn if there are any. 28 | 29 | It will then loop through all of the group names and create groups with the [create_group](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#create_group) post request. 30 | 31 | --- 32 | 33 | ## CloudCheckr Group Ids 34 | 35 | Every group will have a unique group id. This will be a UUID number. 36 | 37 | --- 38 | 39 | ## Contact 40 | 41 | Alec Rajeev - Technical Support Engineer - Tier II 42 | alec.rajeev@cloudcheckr.com -------------------------------------------------------------------------------- /Cost/FindUnmappedAccounts/README.md: -------------------------------------------------------------------------------- 1 | # Find Unmapped Accounts 2 | 3 | Searches CloudCheckr account for any accounts which are not mapped to an account family. If it finds any, it notifies an email address via SES. SES was chosen over SNS for its ability to render HTML messages. 4 | 5 | The script runs during business hours by default, but this behavior can be modified by cron expression. 6 | 7 | ## Prerequisites 8 | 9 | 1. At least one AWS payer account configured as a CloudCheckr project 10 | 2. A CloudCheckr [admin API key](https://success.cloudcheckr.com/article/gbnfxmoyo6-) 11 | * Encrypt this key as a secure string named `cc_admin_access_key` in Systems Manager parameter store and note the KMS key used for the encryption 12 | 3. A Systems Manager parameter (normal string) named `html_encoded_semicolon_separated_master_payers` with the value(s) of the project names for AWS payer accounts in CloudCheckr, [html encoded](https://codebeautify.org/html-encode-string) and delimited by `;` 13 | 4. A verified email address in SES for source email address, and either a verified email or [production mode](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/request-production-access.html) active in the account for sending to the destination address 14 | 15 | ## Launch Instructions 16 | 17 | 1. Create a deployment package for the Lambda function 18 | * Clone to your local desktop 19 | * [Install NodeJS](https://nodejs.org/en/download/) if not already on your machine 20 | * In the the cloned directory, run `npm install` (with no options). This will create a directory called node_modules and will install dependencies based on package.json 21 | * Zip the node_modules folder and the validate_cc_acct_fams.js file together 22 | 2. Upload the zip to S3 23 | 3. Create a CloudFormation stack from [FindUnmappedAccounts.json](FindUnmappedAccounts.json) with the appropriate parameters 24 | -------------------------------------------------------------------------------- /Security/CloudTrail/get_cloudtrail_alerts.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import numpy as np 4 | import sys 5 | 6 | """ 7 | This python script is used to add cost alerts to all non mav AWS accounts 8 | python3 get_cloudtrail_alerts.py 0000000000000000000000000000000000000000000000000000000000000000 9 | """ 10 | 11 | def log_information(log_string): 12 | print(log_string) 13 | 14 | 15 | def get_cloudtrail_alerts(admin_api_key, env, account_name): 16 | 17 | if check_invalid_env(env): 18 | return 19 | 20 | api_url = env + "/api/alert.json/get_cloudtrail_alert_results_v2?access_key=" + admin_api_key + "&use_account=" + account_name 21 | 22 | r7 = requests.get(api_url) 23 | 24 | print(r7.json()) 25 | 26 | 27 | def check_invalid_env(env): 28 | """ 29 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 30 | If you are using a standalone environment, then you MUST add that to this function 31 | """ 32 | 33 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 34 | 35 | 36 | if not(env in Enviroments): 37 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 38 | return True 39 | return False 40 | 41 | 42 | def main(): 43 | try: 44 | admin_api_key = str(sys.argv[1]) 45 | except IndexError: 46 | print("Must include non-admin API key of account that you want to pull via") 47 | return 48 | 49 | env = "https://api.cloudcheckr.com" 50 | 51 | # enter name of account here 52 | account_name = "Account Name Here" 53 | 54 | get_cloudtrail_alerts(admin_api_key, env, account_name) 55 | 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /Inventory/GetEC2Instances/output.json: -------------------------------------------------------------------------------- 1 | [{'HostId': '', 'Instance': 'i-00000000000000000 (AIO)', 'InstanceId': 'i-00000000000000000', 'InstanceName': 'AIO', 'Status': 'stopped', 'Cost': 55.0, 'Region': 'US East (Northern Virginia)', 'PricingType': 'OnDemand', 'Platform': 'Windows', 'PricingPlatform': 'WindowsSqlStandardVpc', 'InstanceType': 'm5.2xlarge', 'AvailabilityZone': 'us-east-1a', 'AttachmentCount': 2, 'TotalVolumeSizeGiB': 550, 'AMI': 'ami-00000000', 'LaunchTime': '2018-10-12T13:11:01', 'MonitoringState': 'disabled', 'PrivateDnsName': 'ip-10-0-0-0.ec2.internal', 'PrivateIpAddress': '10.0.0.0', 'PublicDnsName': None, 'PublicIpAddress': None, 'RamDiskId': None, 'SourceDestinationCheck': True, 'StateReasonCode': 'Client.UserInitiatedShutdown', 'StateReasonMessage': 'Client.UserInitiatedShutdown: User initiated shutdown', 'StateTransitionMessage': 'User initiated (2018-10-12 13:15:21 GMT)', 'SubnetId': 'subnet-00000000', 'VirtualizationType': 'hvm', 'VpcId': 'vpc-00000000', 'Tenancy': 'Default', 'Ec2Cost': 0.0, 'EbsCost': 55.0, 'AvgCpuforLast7Days': None, 'AvgCpuforLast30Days': None, 'AvgCpuforLast90Days': None, 'AvgNetworkInLast30Days': 0.0, 'AvgNetworkOutLast30Days': 0.0, 'HighCpuPercent': 90, 'LowCpuPercent': 5, 'HoursCpuUtilAbove80': 0, 'HoursCpuUtilBelow80': 0, 'HoursCpuUtilBelow60': 0, 'HoursCpuUtilBelow40': 0, 'HoursCpuUtilBelow20': 0, 'HoursHighCpuLast7Days': 0, 'HoursHighCpuLast30Days': 0, 'HoursHighCpuLast90Days': 0, 'HoursLowCpuLast7Days': 0, 'HoursLowCpuLast30Days': 0, 'HoursLowCpuLast90Days': 649, 'HoursRunningLast7Days': None, 'HoursRunningLast30Days': None, 'HoursRunningLast90Days': 651, 'MinimumCpuUtilization': 0.0, 'MinimumCpuUtilizationDateTime': '0001-01-01T00:00:00', 'PeakCpuUtilization': 0.0, 'PeakCpuUtilizationDateTime': '0001-01-01T00:00:00', 'ResourceTags': [{'Key': 'AMI', 'Value': None}, {'Key': 'Name', 'Value': 'AIO'}], 'SecurityGroups': [{'GroupId': 'sg-00000000', 'GroupName': 'Test'}], 'AccountName': None}] 2 | -------------------------------------------------------------------------------- /Cost/AwsSppDiscounts/README.md: -------------------------------------------------------------------------------- 1 | # AWS SPP Discounts with the CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 1. Install python 3, https://www.python.org/downloads/ 8 | 2. Install requests, logging, and csv libraries with pip 9 | 3. Log into CloudCheckr and create an Admin API access key at Admin Functions >> Admin API Key, https://app.cloudcheckr.com/Project/GlobalApiCredentials 10 | 4. Run python aws_spp_discounts.py 11 | 12 | --- 13 | 14 | ## How the program works 15 | 16 | Uses AWS provided file to add accounts to corresponding Custom Billing Charge buckets. 17 | 18 | If a Custom Billing Charge bucket is empty, it asks that the Custom Billing Charge be deleted. Custom Billing Charges must include at least one account. 19 | 20 | Uses [get_custom_billing_charges_v3](https://success.cloudcheckr.com/article/kr5glkrmon-admin-api-reference-guide#get_custom_billing_charges_v3) API call to get custom billing charge data for edit_custom_billing_charge_monthly_percent API call. 21 | 22 | Uses [edit_custom_billing_charge_monthly_percent](https://success.cloudcheckr.com/article/kr5glkrmon-admin-api-reference-guide#edit_custom_billing_charge_monthly_percent) API call to add accounts to Custom Billing Charge configurations. 23 | 24 | The payer project id is the CloudCheckr project id of the AWS Payer account. 25 | 26 | Custom Billing Charges can be viewed through the UI at Cost >> AWS Partner Tools >> Configure >> Custom Billing Charges. 27 | 28 | --- 29 | 30 | ## Assumptions 31 | 32 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 178 if required. 33 | 2. The Custom Billing Charge names are defined on lines 102 to 118. If names do not match current Custom Billing Charge configuration, please redefine names. 34 | 3. Convert AWS provided file to CSV and place within same directory as aws_spp_discounts.py. The file name is set on line 27. 35 | -------------------------------------------------------------------------------- /Onboarding/AddUsers/README.md: -------------------------------------------------------------------------------- 1 | # Use CloudCheckr's API to Add Users 2 | 3 | The purpose of this script is to add users to CloudCheckr with the CloudCheckr Api. 4 | 5 | --- 6 | 7 | ## Steps to Setup Input File 8 | 9 | 1. Navigate to the AddUsers folder. 10 | 2. In the first column write the environment such as https://api.cloudcheckr.com 11 | 3. In the second column unique email that you want to add. 12 | 4. In the third column add the role that you want that user to have. The available options are Administrator, User, BasicPlusUser, BasicUser, ReadonlyUser. 13 | 4. Repeat the above for as many users that you want to create. 14 | 15 | --- 16 | 17 | ## Steps to Run Add Users program 18 | 19 | 1. Run the python program add_users.py. 20 | 2. You must put the admin api key as a command line input. An example is below. 21 | 3. python add_users.py 0000000000000000000000000000000000000000000000000000000000000000 22 | 4. If this runs as expected, it will ouput a csv file called UsersCreated with all of the users created. 23 | 24 | --- 25 | 26 | ## How this program works. 27 | 28 | This program will read the user emails from the user input template csv file using pandas [read_csv](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html). These user names must be unique. The list of current users will be downloaded with [get_users](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_users) to get a list of current users. 29 | 30 | It will then loop through all of the user names and add the user with the [add_user](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#add_user) post request. 31 | 32 | --- 33 | 34 | ## CloudCheckr User Id 35 | 36 | Every user will have a unique user id. This will be a UUID number. 37 | 38 | --- 39 | 40 | ## Contact 41 | 42 | Alec Rajeev - Technical Support Engineer - Tier II 43 | alec.rajeev@cloudcheckr.com -------------------------------------------------------------------------------- /Security/ChangeMonitoring/get_change_monitoring_events.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import numpy as np 4 | import sys 5 | 6 | """ 7 | This python script is used to add cost alerts to all non mav AWS accounts 8 | python get_change_monitoring.py 0000000000000000000000000000000000000000000000000000000000000000 9 | """ 10 | 11 | def log_information(log_string): 12 | print(log_string) 13 | 14 | 15 | def get_changes(admin_api_key, env, account_name): 16 | 17 | if check_invalid_env(env): 18 | return 19 | 20 | api_url = env + "/api/change_monitoring.json/get_changes" 21 | 22 | change_monitoring_info = json.dumps({"use_account": account_name}) 23 | 24 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = change_monitoring_info) 25 | 26 | print(r7.json()) 27 | 28 | 29 | def check_invalid_env(env): 30 | """ 31 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 32 | If you are using a standalone environment, then you MUST add that to this function 33 | """ 34 | 35 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 36 | 37 | 38 | if not(env in Enviroments): 39 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 40 | return True 41 | return False 42 | 43 | 44 | def main(): 45 | try: 46 | admin_api_key = str(sys.argv[1]) 47 | except IndexError: 48 | print("Must include non-admin API key of account that you want to pull via") 49 | return 50 | 51 | env = "https://api.cloudcheckr.com" 52 | 53 | account_name = "Account Name Here" 54 | 55 | 56 | get_changes(admin_api_key, env, account_name) 57 | 58 | 59 | if __name__ == '__main__': 60 | main() 61 | -------------------------------------------------------------------------------- /Cost/DeleteCustomCharges/README.md: -------------------------------------------------------------------------------- 1 | **Delete Custom Charges with the CloudCheckr API** 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy, and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the CloudCheckr Account name of the payer account to line 48 in the variable payer_account_name. 12 | 5. Make sure that the add_charges.csv file is formatted correctly and in the same directory as the script. 13 | 6. Run python delete_custom_charges.py 14 | 15 | --- 16 | 17 | ## How the program works 18 | 19 | It uses the [delete_custom_billing_charge_fixed](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#delete_custom_billing_charge_fixed) Admin API call to delete a fixed custom billing charge. 20 | 21 | 22 | You can confirm the custom charges that were removed by going to the corresponding payer account and Cost -> AWS Partner Tools -> Configure -> Custom Billing Charges. 23 | 24 | --- 25 | 26 | ## How To Setup the Custom Charges 27 | 28 | The program requires a specific input for the custom charges csv file in order to run. You should open up the added_charges.csv file and edit it to fit your team's requirements. 29 | 30 | The first column should be the id of the fixed custom charge. The id can be found by using the [get_custom_billing_charges_v3](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_custom_billing_charges_v3) API call. It will also be saved as an output in the AddCustomCharges file. 31 | 32 | --- 33 | 34 | ## Assumptions 35 | 36 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 46 if required. 37 | 2. Only fixed one time custom charges specified in the input file added_charges.csv are to be removed. -------------------------------------------------------------------------------- /Cost/AddCustomCharges/README.md: -------------------------------------------------------------------------------- 1 | **Add Fixed Custom Charges with the CloudCheckr API** 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy, and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the CloudCheckr Account name of the payer account to line 90 in the variable payer_account_name. 12 | 5. Make sure the custom_charges.csv file is formmated correctly and in the same directory as the script. 13 | 6. Run python upload_custom_charges.py 14 | 15 | --- 16 | 17 | ## How the program works 18 | 19 | It uses the [add_custom_billing_charge_fixed](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#add_custom_billing_charge_fixed) Admin API call to add a fixed custom billing charge. 20 | 21 | 22 | You can view the custom charges that were added by going to the corresponding payer account and Cost -> AWS Partner Tools -> Configure -> Custom Billing Charges. 23 | 24 | --- 25 | 26 | ## How To Setup the Custom Charges 27 | 28 | The program requires a specific input for the custom charges csv file in order to run. You should open up the custom_charges.csv file and edit it to fit your team's requirements. The first line is Account,Amount,startDate,endDate,Description. 29 | 30 | The first column should be the twelve digit AWS Account Id of a payee account that is part of the payer that was specified. The second column should be the amount of the fixed custom charge. The third column should be the start date of the charge in year-month-date format (such as 2018-07-01). The last column is the end date of the charge is the same date format. 31 | 32 | --- 33 | 34 | ## Assumptions 35 | 36 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 88 if required. 37 | 2. Only fixed one time custom charges are to be added. -------------------------------------------------------------------------------- /Cost/AddCostAlerts/logging_for_add_cost_alerts.log: -------------------------------------------------------------------------------- 1 | INFO:root:Started adding cost alerts 2 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 23 3 | INFO:root:{'Code': 200, 'Message': 'OK'} 4 | INFO:root: 5 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 24 6 | INFO:root:{'Code': 200, 'Message': 'OK'} 7 | INFO:root: 8 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 25 9 | INFO:root:{'Code': 200, 'Message': 'OK'} 10 | INFO:root: 11 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 29 12 | INFO:root:{'Code': 200, 'Message': 'OK'} 13 | INFO:root: 14 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 30 15 | INFO:root:{'Code': 200, 'Message': 'OK'} 16 | INFO:root: 17 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 31 18 | INFO:root:{'Code': 200, 'Message': 'OK'} 19 | INFO:root: 20 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 32 21 | INFO:root:{'Code': 200, 'Message': 'OK'} 22 | INFO:root: 23 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 33 24 | INFO:root:{'Code': 200, 'Message': 'OK'} 25 | INFO:root: 26 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 34 27 | INFO:root:{'Code': 200, 'Message': 'OK'} 28 | INFO:root: 29 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 38 30 | INFO:root:{'Code': 200, 'Message': 'OK'} 31 | INFO:root: 32 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 44 33 | INFO:root:{'Code': 200, 'Message': 'OK'} 34 | INFO:root: 35 | INFO:root:Successfully added the cost alert Onboarding Alert Api to the CloudCheckr account with id 45 36 | INFO:root:{'Code': 200, 'Message': 'OK'} 37 | INFO:root: 38 | INFO:root:Finished adding cost alerts 39 | -------------------------------------------------------------------------------- /Cost/AwsCostAdvancedGrouping/process_cost.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import numpy as np 4 | import sys 5 | import pandas as pd 6 | from pandas.io.json import json_normalize 7 | 8 | """ 9 | This python script is used to find cost per customer id. 10 | python ProcessCost.py 0000000000000000000000000000000000000000000000000000000000000000 "MonthlyTotal-CC" "2020-03-01" "2020-03-31" 11 | """ 12 | 13 | def get_cc_cost(env, admin_api_key, saved_filter_name, cc_account_name, start_date, end_date): 14 | """ 15 | Get cost from CloudCheckr Core Billing API 16 | """ 17 | 18 | api_url = env + "/api/billing.json/get_detailed_billing_with_grouping_v2" 19 | saved_filter_info = json.dumps({"saved_filter_name": saved_filter_name, "use_account": cc_account_name, "start": start_date, "end": end_date}) 20 | 21 | 22 | request_output = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data=saved_filter_info, timeout=1000) 23 | 24 | if "CostsByGroup" in request_output.json(): 25 | CostsByGroup = request_output.json()["CostsByGroup"] 26 | normalized = json_normalize(CostsByGroup) 27 | 28 | return normalized[['GroupValue', 'Cost']] 29 | else: 30 | print("Error from CC API") 31 | print(request_output.json()) 32 | 33 | def save_to_csv(normalized): 34 | """ 35 | Save data to csv file 36 | """ 37 | 38 | normalized.to_csv('cost_by_service.csv', index=False) 39 | 40 | def main(): 41 | try: 42 | admin_api_key = str(sys.argv[1]) 43 | saved_filter_name = str(sys.argv[2]) 44 | start_date = str(sys.argv[3]) 45 | end_date = str(sys.argv[4]) 46 | except IndexError: 47 | print("Must have an admin_api_key, start date, and end date as arguments") 48 | return 49 | 50 | # environment to pull cost data 51 | env = "https://api.cloudcheckr.com" 52 | 53 | # name of the account in cloudcheckr 54 | cc_account_name = "Test Payer" 55 | 56 | normalized1 = get_cc_cost(env, admin_api_key, saved_filter_name, cc_account_name, start_date, end_date) 57 | normalized1 = normalized1.rename(columns={'Cost': 'Dec2020'}) 58 | 59 | save_to_csv(normalized1) 60 | 61 | 62 | 63 | if __name__ == '__main__': 64 | main() -------------------------------------------------------------------------------- /Onboarding/AddUsersToGroups/README.md: -------------------------------------------------------------------------------- 1 | # Use CloudCheckr's API to Add Users To Groups 2 | 3 | The purpose of this script is to add users to groups with the CloudCheckr Api. 4 | 5 | --- 6 | 7 | ## Steps to Setup Input File 8 | 9 | 1. Navigate to the AddUsers folder. 10 | 2. In the first column write the environment such as https://api.cloudcheckr.com 11 | 3. In the second column write the email of the user that you want to add to a group. 12 | 4. In the third column write the group name that you wish to add that user to. 13 | 4. Repeat the above for as many users that you want to add to groups. 14 | 15 | --- 16 | 17 | ## Steps to Run Add Users program 18 | 19 | 1. Run the python program add_users_to_groups.py. 20 | 2. You must put the admin api key as a command line input. An example is below. 21 | 3. python add_users_to_groups.py 0000000000000000000000000000000000000000000000000000000000000000 22 | 4. If this runs as expected, it will log all of the users that were added to groups on the command line. 23 | 24 | --- 25 | 26 | ## How this program works. 27 | 28 | This program will read the users and groups from the add_users_to_groups input template csv file using pandas [read_csv](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html). 29 | 30 | It will then generate a numpy array to connect group names to group id with a get request on [get_groups_v2](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_groups_v2). 31 | 32 | It will then loop through all of the user names (emails) and ge the user id with a post request on [get_user_v2](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_user_v2) using the email as an input. 33 | 34 | With the corresponding user id and group id, it will then add the user to the group with [add_user_to_group](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#add_user_to_group). Every user added to a group will be logged to the command line. 35 | 36 | --- 37 | 38 | ## CloudCheckr User Id 39 | 40 | Every user will have a unique user id. This will be a UUID number. 41 | 42 | --- 43 | 44 | ## CloudCheckr Group Id 45 | 46 | Every user will have a unique group id. This will be a UUID number. 47 | 48 | --- 49 | 50 | ## Contact 51 | 52 | Alec Rajeev - Technical Support Engineer - Tier II 53 | alec.rajeev@cloudcheckr.com -------------------------------------------------------------------------------- /Cost/AddSavedFilters/logging_for_add_saved_filter.log: -------------------------------------------------------------------------------- 1 | INFO:root:Started adding saved filters 2 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 23 3 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 4 | INFO:root: 5 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 24 6 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 7 | INFO:root: 8 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 25 9 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 10 | INFO:root: 11 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 26 12 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 13 | INFO:root: 14 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 27 15 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 16 | INFO:root: 17 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 29 18 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 19 | INFO:root: 20 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 30 21 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 22 | INFO:root: 23 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 31 24 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 25 | INFO:root: 26 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 32 27 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 28 | INFO:root: 29 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 33 30 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 31 | INFO:root: 32 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 34 33 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 34 | INFO:root: 35 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 38 36 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 37 | INFO:root: 38 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 44 39 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 40 | INFO:root: 41 | INFO:root:Successfully added the cost alert Saved Filter API to the CloudCheckr account with id 45 42 | INFO:root:{'Code': 200, 'Message': 'Successfully saved search.'} 43 | INFO:root: 44 | INFO:root:Finished adding saved filters 45 | -------------------------------------------------------------------------------- /Cost/ClearAccountFamilies/README.md: -------------------------------------------------------------------------------- 1 | **Clear Account Families with the CloudCheckr API** 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install numpy, and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html 10 | 3. Log in to CloudCheckr and create an Admin API access key. 11 | 4. Enter the CloudCheckr Account name of the payer account to line 59 in the variable payer_account_name. 12 | 5. Set up the payer's account family following the process below. 13 | 6. Run the below. 14 | 15 | 16 | python clear_account_families.py admin-api-key 17 | 18 | --- 19 | 20 | ## How the program works 21 | 22 | It uses the [get_account_family](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_account_family) Admin API call to get a list of all account families. 23 | 24 | It uses the [delete_account_family](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#delete_account_family) Admin API call to delete all of the the account families except one that is specified. 25 | 26 | You can confirm the account families were removed by going to Cost -> AWS Partner Tools -> Configure -> Account Families. 27 | 28 | --- 29 | 30 | ## How to Set Up Payer Account Family 31 | 32 | For historical reasons, you can no longer delete all account families from a payer if some have already been created. It is 33 | recommended that you create a single account family that contains the payer and name it Payer Account Family. This will 34 | exist as a placeholder. You may have to manually remove the payer from an existing Account Family and create a new Account Family 35 | with it. This new Account Family should be called Payer Account Family. 36 | 37 | The script will download all Account Families and identify the account family with the payer by looking for an Account Family 38 | with the name Payer Account Family. This account family will not be deleted and will be left as a placeholder. 39 | 40 | Once the script completes you can then create new account families to fit your requirements. It is recommended not to delete the placeholder 41 | account family until another account family is created. 42 | 43 | If the Payer Account Family is not found, then the script will exit without deleting anything. Once the Payer Account Family is identified, the script will proceed with the deletion. You can change the name of the Payer Account Family by editing line 60. 44 | 45 | --- 46 | 47 | ## Assumptions 48 | 49 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 57 if required such is if you are using https://eu.cloudcheckr.com. 50 | -------------------------------------------------------------------------------- /Onboarding/ModifyUsers/modify_users.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import sys 4 | import logging 5 | logging.basicConfig(filename='logging_for_modify_users.log',level=logging.INFO) 6 | 7 | """ 8 | This python script is used to modify users based on a specified criteria and desired result 9 | python3 modify_users.py 0000000000000000000000000000000000000000000000000000000000000000 10 | """ 11 | 12 | def log_information(log_string): 13 | logging.info(log_string) 14 | print(log_string) 15 | 16 | 17 | def get_users_v2(admin_api_key, env): 18 | """ 19 | Uses admin API key to get user data 20 | """ 21 | 22 | half_url = f"{env}/api/account.json/get_users_v2" 23 | api_parameters = {} 24 | resp = requests.get(half_url, params=api_parameters, headers = {"access_key": admin_api_key}) 25 | 26 | users = [] 27 | 28 | if "user_permissions" in resp.json(): 29 | user_data = resp.json()["user_permissions"] 30 | for user in user_data: 31 | if user["role"] == "PartnerSysAdmin": 32 | users.append(user["email"]) 33 | else: 34 | log_information("Unable to obtain user data") 35 | 36 | return users 37 | 38 | 39 | def edit_user(admin_api_key, env, user): 40 | """ 41 | Uses admin API key to modify user 42 | """ 43 | 44 | half_url = f"{env}/api/account.json/edit_user" 45 | api_parameters = {"email": user, "role": "Administrator"} 46 | resp = requests.post(half_url, data=json.dumps(api_parameters), headers = {"Content-type": "application/json", "access_key": admin_api_key}) 47 | 48 | if "Code" in resp.json(): 49 | log_information(f"Modified user with email: {user}") 50 | else: 51 | log_information(f"Failed to modify user with email: {user}") 52 | 53 | 54 | def validate_env(env): 55 | """ 56 | Validates environment. By default, it checks for api, eu, au, gov and qa. 57 | If you are using a standalone environment, then you must add it to the environments list 58 | """ 59 | 60 | enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 61 | 62 | if env not in enviroments: 63 | log_information(f"The environment {env} is not valid. If this is a standalone environment, please add the url to the validate_env function.") 64 | 65 | 66 | def main(): 67 | try: 68 | admin_api_key = str(sys.argv[1]) 69 | except IndexError: 70 | log_information("Must include admin API key") 71 | return 72 | 73 | env = "https://api.cloudcheckr.com" 74 | validate_env(env) 75 | 76 | users = get_users_v2(admin_api_key, env) 77 | for user in users: 78 | edit_user(admin_api_key, env, user) 79 | 80 | 81 | if __name__ == '__main__': 82 | main() -------------------------------------------------------------------------------- /CloudFormationTemplate/CF_Template_README.md: -------------------------------------------------------------------------------- 1 | # CloudFormation Template 2 | 3 | A cross-account role allows you to share resources across AWS accounts. Since your cross-account role works globally, you don't need IAM users to sign in and out of accounts to access these resources. 4 | 5 | The CloudFormation template is an alternative to creating a cross-account role manually. It is a JSON file pre-configured with all the parameters and provisions you need to access your AWS resources across multiple accounts in your cloud environment. This template allows AWS to standardize permissions across your deployment automatically. 6 | 7 | To view a detailed list of instructions, please go to https://success.cloudcheckr.com/article/3ldmqs5pzn-creating-aws-credentials-with-cloud-formation for more details. 8 | 9 | Please note, our CloudFormation template is only intended to credential Commercial AWS Accounts. For GovCloud accounts, IAM Access Keys will be required, more details can be found at https://success.cloudcheckr.com/article/99vns4x2ho-configure-gov-cloud-account-iam-access-keys. 10 | 11 | ## Policy Structure Notes 12 | 13 | ### Unauthorized Access 14 | 15 | CloudCheckr will attempt to ingest data from all of the AWS core features to populate the Cost, Billing, Security, Inventory, and CloudWatch Flow Log reports. Since CloudCheckr must make calls even to those categories where you have not enabled permissions, you will see "Unauthorized Access" attempts in your CloudTrail logs. These logs are only an indication of the CloudCheckr workflow and in no way reflect an attempt on the part of CloudCheckr to collect unauthorized information from customers. 16 | 17 | ### s3:GetObject 18 | 19 | To help you maintain a secure, least privilege configuration, CloudCheckr's Security/Compliance policy does not include any `s3:GetObject` permissions. However, you can add add the `s3:GetObject` permission to the following reports: 20 | 21 | * S3 Encryption Details report: enables CloudCheckr scan your encrypted S3 buckets. 22 | * We recommend restricting this permission to only selected S3 bucket(s). 23 | 24 | * List of VPCs report: enables CloudCheckr to ingest data from the Elastic Beanstalk applications for this report. 25 | * The default Security/Compliance policy will only display 0 as the number of Elastic Beanstalk applications within a VPC. 26 | 27 | ### s3:GetEncryptionConfigruation 28 | 29 | As per the latest AWS requirements, CloudCheckr's CloudFormation template and the Inventory policy do not include the "s3:GetEncryptionConfiguration" by default. 30 | However, without this permission, CloudCheckr cannot get the information it needs to report on the "S3 Bucket Without Default Encryption Enabled" Best Practice Check (BPC). If you decide not to add this permission to your policy, we recommend that you ignore or disable this BPC to avoid any false negatives. 31 | -------------------------------------------------------------------------------- /Cost/QuickBooksInvoices/README.md: -------------------------------------------------------------------------------- 1 | # QuickBooks Invoices with CloudCheckr API 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 1. Install Python 3, https://www.python.org/downloads/ 8 | 2. Install requests, logging, and datetime libraries with pip 9 | 3. Log into CloudCheckr and create an Admin API access key at Admin Functions >> Admin API Key, https://app.cloudcheckr.com/Project/GlobalApiCredentials 10 | 5. Log into QuickBooks and create an App, https://developer.intuit.com/app/developer/myapps 11 | 6. Select the App and generate an Access Token via OAuth 2.0 with an Accounting scope, https://developer.intuit.com/app/developer/playground 12 | 7. Run python quickbooks_invoices.py 13 | 14 | --- 15 | 16 | ## How the program works 17 | 18 | Uses [get_detailed_billing_with_grouping_v2](https://success.cloudcheckr.com/article/7sskuffbg6-api-reference-guide#list_results_from_an_advanced_grouping_saved_filter) API to get Saved Filter data from CloudCheckr for QuickBooks Invoice API. 19 | 20 | Uses item [query](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/item#query-an-item) & customer [query](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/customer#query-a-customer) API to get Item and Customer data from QuickBooks for QuickBooks Invoice API. 21 | 22 | Uses [item](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/item#create-an-item) API to create Items in QuickBooks for QuickBooks Invoice API. 23 | 24 | Uses [invoice](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/invoice) API to create Invoices in QuickBooks. 25 | 26 | The payer project ID is the CloudCheckr project ID of the AWS Payer account. Project ID information can be obtained using the [get_accounts_v4](https://success.cloudcheckr.com/article/kr5glkrmon-admin-api-reference-guide#get_accounts_v4) API. Project ID is also known as cc_account_id. 27 | 28 | Saved Filters can be viewed through the CloudCheckr UI at Cost >> AWS Billing >> Custom Reporting >> Advanced Grouping. 29 | 30 | --- 31 | 32 | ## Assumptions 33 | 34 | 1. The CloudCheckr environment is set at https://api.cloudcheckr.com. It can be adjusted on line 249 if required. 35 | 2. The QuickBooks environment is set at https://sandbox-quickbooks.api.intuit.com. It can be adjusted on line 252 if required. 36 | 3. The QuickBooks Account ID needs to be set. It can be adjusted on line 262. 37 | 4. The QuickBooks customer "DisplayName" and CloudCheckr "Saved Filter" name must match in order to successfully generate an invoice. 38 | 5. Saved Filter used must contain at least two group-by levels. The first group-by level will map to the "Service" attribute and the second group-by level will map to the "Activity" attribute. The "Service" and "Activity" attributes will be included as part of the QuickBooks invoice. 39 | -------------------------------------------------------------------------------- /Offboarding/delete_accounts.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import pandas as pd 4 | import numpy as np 5 | import sys 6 | import logging 7 | 8 | 9 | """ 10 | 1) This python script is used to delete accounts based on the list of accounts provided in a csv file named 'accounts_list'. Please see example datafile for formatting. 11 | 2) For the data file, please define 2 columns: 12 | Column 1: the API URI for your region in CloudCheckr 13 | Valid regions: 14 | https://api.cloudcheckr.com 15 | https://eu.cloudcheckr.com 16 | https://au.cloudcheckr.com 17 | https://gov.cloudcheckr.com 18 | Column 2: the corresponding account name of the account you wish to be deleted (as it appears in the CloudCheckr landing page) 19 | Note: The first row is for column names 20 | 3) To call this script, use the following: python3 delete_accounts.py 21 | 4) Please ensure that this file is in the same folder/directory as the data file. 22 | """ 23 | 24 | 25 | logging.basicConfig(filename='logging_for_deleting_accounts.log',level=logging.INFO) 26 | 27 | def get_accounts_input(file_name): 28 | accounts_list = pd.read_csv(file_name) 29 | return accounts_list 30 | 31 | def delete_account(env, admin_api_key, account_name): 32 | api_url = env + "/api/account.json/delete_account" 33 | delete_user_info = json.dumps({"account_name": account_name}) 34 | 35 | try: 36 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = delete_user_info) 37 | if r7.status_code == 200: 38 | logging.info("Success: {}, request to '{}' with parameters '{}'".format(r7.status_code, api_url, delete_user_info)) 39 | 40 | else: 41 | # If an error is logged as a WARNING due to this else clause, an error code should be returned. This code can be looked up by CloudCheckr Support to assist with debugging. 42 | logging.warning("Request to {} Failed: {}, Request parameters '{}'\n{}".format(api_url, r7.status_code, delete_user_info, r7.json())) 43 | 44 | except requests.exceptions.RequestException as e: 45 | logging.critical('Request Exception: {}'.format(e)) 46 | 47 | def cycle_delete_accounts(admin_api_key, accounts_list): 48 | logging.info("Started deleting accounts") 49 | for i in np.arange(0, np.shape(accounts_list)[0]): 50 | delete_account(accounts_list.iloc[i][0], admin_api_key, accounts_list.iloc[i][1]) 51 | 52 | logging.info("Finished deleting accounts") 53 | return 1 54 | 55 | def main(): 56 | file_name = "accounts_list.csv" 57 | accounts_input = get_accounts_input(file_name) 58 | 59 | try: 60 | admin_api_key = sys.argv[1] 61 | except IndexError: 62 | print("Need admin_api_key in input") 63 | sys.exit() 64 | 65 | cycle_delete_accounts(admin_api_key, accounts_input) 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /Cost/ClearAccountFamilies/clear_account_families.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import json 3 | import requests 4 | import sys 5 | 6 | # python clear_account_families.py 7 | 8 | 9 | def get_account_families(env, admin_api_key, payer_account_name): 10 | api_url = env + "api/billing.json/get_account_family_v2?access_key=" + admin_api_key + "&use_account=" + payer_account_name 11 | 12 | response = requests.get(api_url) 13 | if "AccountFamilies" in response.json(): 14 | AccountFamilies = response.json()["AccountFamilies"] 15 | # print(AccountFamilies) 16 | return AccountFamilies 17 | else: 18 | print("Could not find any account families") 19 | print(response.json()) 20 | return None 21 | 22 | 23 | def clear_account_families(env, admin_api_key, AccountFamilies, payer_account_name, payer_account_family): 24 | api_url_base = env + "api/billing.json/delete_account_family" 25 | 26 | payer_account_family_missing = True 27 | for i in np.arange(0, np.shape(AccountFamilies)[0]): 28 | if AccountFamilies[i]["Name"] == payer_account_family: 29 | payer_account_family_missing = False 30 | break 31 | if payer_account_family_missing: 32 | print("Could not find an Account Family named " + payer_account_family) 33 | print("It is recommended that you create a placeholder account family that contains the payer and name it " + payer_account_family) 34 | return 35 | for i in np.arange(0, np.shape(AccountFamilies)[0]): 36 | api_url = api_url_base 37 | if not(AccountFamilies[i]["Name"] == payer_account_family): 38 | api_url = api_url + "?access_key=" + admin_api_key + "&use_account=" + payer_account_name + "&name=" + AccountFamilies[i]["Name"] 39 | response = requests.get(api_url) 40 | if "ModelState" in response.json() or "ErrorMessage" in response.json(): 41 | print("Failed to delete the account family " + AccountFamilies[i]["Name"]) 42 | print(response.json()) 43 | else: 44 | print("Successfully deleted the account family " + AccountFamilies[i]["Name"]) 45 | print(response.json()) 46 | else: 47 | print("Skipping the deletion of the account family " + payer_account_family) 48 | print("Finished deleting account families") 49 | 50 | def main(): 51 | try: 52 | admin_api_key = str(sys.argv[1]) 53 | except IndexError: 54 | print("Must admin_api_key") 55 | return 56 | 57 | env = "https://api.cloudcheckr.com/" 58 | 59 | payer_account_name = "Payer Master Account" # Name of the Payer Account in CloudCheckr 60 | payer_account_family = "Payer Account Family" # Name of the Account Family that contains the payer. (This account family will NOT be deleted) 61 | AccountFamilies = get_account_families(env, admin_api_key, payer_account_name) 62 | if AccountFamilies is None: 63 | return 64 | clear_account_families(env, admin_api_key, AccountFamilies, payer_account_name, payer_account_family) 65 | 66 | 67 | if __name__ == "__main__": 68 | main() 69 | -------------------------------------------------------------------------------- /Onboarding/AddAzureAccounts/add_azure_account.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import boto3 3 | import requests 4 | import sys 5 | import json 6 | import time 7 | 8 | """ 9 | To run this you use python add_azure_account.py 10 | 11 | To run this are the following input parameters cloudcheckr-admin-api-key unique-account-name-in-cloudcheckr azure-active-directory-id azure-application-id azure-application-secret azure-subscription-id 12 | 13 | The CloudCheckr admin api key is a 64 character string. 14 | The CloudCheckr Account name is the name of the new account in CloudCheckr. 15 | The azure-active-directory-id is the GUID directory id. This will generally be the same for all subscriptions that have the same parent. (Parent being their associated CSP or EA account that contains cost data) 16 | The azure-application-id is the GUID id of the application that was created previously. It can be re-used for multiple subscriptions, but have to give the application permissions in each subscription. 17 | The azure-application-secret is the secret key that was created previously. This is shown only once when generating the key. It can last 1 year, 2 years, or forever. 18 | The azure-subscription-id is the GUID that corresponds to the id of the subscription. This subscription will be different for every account that is added to CloudCheckr. 19 | 20 | """ 21 | 22 | def create_azure_account(env, admin_api_key, account_name, azure_ad_id, azure_app_id, azure_api_access_key, azure_subscription_id): 23 | """ 24 | Creates an Azure Account in CloudCheckr. It will populate it with azure subscription credentials that were provided. 25 | """ 26 | 27 | api_url = env + "/api/account.json/add_azure_inventory_account" 28 | 29 | add_azure_account_info = json.dumps({"account_name": account_name, "azure_ad_id": azure_ad_id, "azure_app_id": azure_app_id, "azure_api_access_key": azure_api_access_key, "azure_subscription_id": azure_subscription_id}) 30 | 31 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = add_azure_account_info) 32 | 33 | print(r7.json()) 34 | 35 | def main(): 36 | try: 37 | admin_api_key = str(sys.argv[1]) 38 | except IndexError: 39 | print("Must include an admin api key in the command line") 40 | return 41 | 42 | try: 43 | account_name = str(sys.argv[2]) 44 | except IndexError: 45 | print("Must include a cloudcheckr account name") 46 | return 47 | 48 | try: 49 | azure_ad_id = str(sys.argv[3]) 50 | except IndexError: 51 | print("Must include an Azure Directory Id") 52 | return 53 | 54 | try: 55 | azure_app_id = str(sys.argv[4]) 56 | except IndexError: 57 | print("Must include an Azure Application Id") 58 | return 59 | 60 | try: 61 | azure_api_access_key = str(sys.argv[5]) 62 | except IndexError: 63 | print("Must include an Azure Api Access Key") 64 | return 65 | 66 | try: 67 | azure_subscription_id = str(sys.argv[6]) 68 | except IndexError: 69 | print("Must include an Azure Subscription Id") 70 | return 71 | 72 | # can change this it eu.cloudcheckr.com or au.cloudcheckr.com for different environments 73 | env = "https://api.cloudcheckr.com" 74 | 75 | create_azure_account(env, admin_api_key, account_name, azure_ad_id, azure_app_id, azure_api_access_key, azure_subscription_id) 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /Inventory/GetIAMUsers/get_iam_users.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import numpy as np 4 | import sys 5 | 6 | """ 7 | This python script is used to get all ec2 instances 8 | python3 get_iam_users.py 0000000000000000000000000000000000000000000000000000000000000000 9 | """ 10 | 11 | def get_token_ec2_instances(admin_api_key, env, account_name, i, next_token): 12 | 13 | # if first time the method is called 14 | if i == 0: 15 | i += 1 16 | api_url = env + "/api/inventory.json/get_resources_iam_users?access_key=" + admin_api_key + "&use_account=" + account_name 17 | r7 = requests.get(api_url) 18 | if "IamUsersDetails" in r7.json(): 19 | print(r7.json()["IamUsersDetails"]) 20 | if "HasNext" in r7.json(): 21 | if r7.json()["HasNext"] == True: 22 | next_token = r7.json()["NextToken"] 23 | return i, False, next_token 24 | else: 25 | return i, True, "0000" 26 | else: 27 | print("Could not find HasNext value") 28 | else: 29 | print("Could not find any instances") 30 | print(r7.json()) 31 | else: 32 | i += 1 33 | api_url = env + "/api/inventory.json/get_resources_iam_users?access_key=" + admin_api_key + "&use_account=" + account_name + "&next_token=" + next_token 34 | r7 = requests.get(api_url) 35 | if "IamUsersDetails" in r7.json(): 36 | print(r7.json()["IamUsersDetails"]) 37 | if "HasNext" in r7.json(): 38 | if r7.json()["HasNext"] == True: 39 | next_token = r7.json()["NextToken"] 40 | return i, False, next_token 41 | else: 42 | return i, True, "0000" 43 | else: 44 | print("Could not find HasNext value") 45 | else: 46 | print("Could not find any instances") 47 | print(r7.json()) 48 | 49 | def get_ec2_instances(admin_api_key, env, account_name): 50 | 51 | if check_invalid_env(env): 52 | return 53 | 54 | finish = False 55 | i = 0 56 | next_token = "00000" 57 | 58 | while finish == False: 59 | i, finish, next_token = get_token_ec2_instances(admin_api_key, env, account_name, i, next_token) 60 | 61 | 62 | def check_invalid_env(env): 63 | """ 64 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 65 | If you are using a standalone environment, then you MUST add that to this function 66 | """ 67 | 68 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 69 | 70 | 71 | if not(env in Enviroments): 72 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 73 | return True 74 | return False 75 | 76 | 77 | def main(): 78 | try: 79 | admin_api_key = str(sys.argv[1]) 80 | except IndexError: 81 | print("Must include non-admin API key of account that you want to pull via") 82 | return 83 | 84 | env = "https://api.cloudcheckr.com" 85 | 86 | # enter name of account here 87 | account_name = "Account Name Here" 88 | 89 | get_ec2_instances(admin_api_key, env, account_name) 90 | 91 | 92 | if __name__ == '__main__': 93 | main() 94 | -------------------------------------------------------------------------------- /Inventory/GetEC2Instances/get_ec2_instances.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import numpy as np 4 | import sys 5 | 6 | """ 7 | This python script is used to get all ec2 instances 8 | python3 get_ec2_instances.py 0000000000000000000000000000000000000000000000000000000000000000 9 | """ 10 | 11 | def get_token_ec2_instances(admin_api_key, env, account_name, i, next_token): 12 | 13 | # if first time the method is called 14 | if i == 0: 15 | i += 1 16 | api_url = env + "/api/inventory.json/get_resources_ec2_details_v4?access_key=" + admin_api_key + "&use_account=" + account_name 17 | r7 = requests.get(api_url) 18 | if "Ec2Instances" in r7.json(): 19 | print(r7.json()["Ec2Instances"]) 20 | if "HasNext" in r7.json(): 21 | if r7.json()["HasNext"] == True: 22 | next_token = r7.json()["NextToken"] 23 | return i, False, next_token 24 | else: 25 | return i, True, "0000" 26 | else: 27 | print("Could not find HasNext value") 28 | else: 29 | print("Could not find any instances") 30 | print(r7.json()) 31 | else: 32 | i += 1 33 | api_url = env + "/api/inventory.json/get_resources_ec2_details_v4?access_key=" + admin_api_key + "&use_account=" + account_name + "&next_token=" + next_token 34 | r7 = requests.get(api_url) 35 | if "Ec2Instances" in r7.json(): 36 | print(r7.json()["Ec2Instances"]) 37 | if "HasNext" in r7.json(): 38 | if r7.json()["HasNext"] == True: 39 | next_token = r7.json()["NextToken"] 40 | return i, False, next_token 41 | else: 42 | return i, True, "0000" 43 | else: 44 | print("Could not find HasNext value") 45 | else: 46 | print("Could not find any instances") 47 | print(r7.json()) 48 | 49 | def get_ec2_instances(admin_api_key, env, account_name): 50 | 51 | if check_invalid_env(env): 52 | return 53 | 54 | finish = False 55 | i = 0 56 | next_token = "00000" 57 | 58 | while finish == False: 59 | i, finish, next_token = get_token_ec2_instances(admin_api_key, env, account_name, i, next_token) 60 | 61 | 62 | def check_invalid_env(env): 63 | """ 64 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 65 | If you are using a standalone environment, then you MUST add that to this function 66 | """ 67 | 68 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 69 | 70 | 71 | if not(env in Enviroments): 72 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 73 | return True 74 | return False 75 | 76 | 77 | def main(): 78 | try: 79 | admin_api_key = str(sys.argv[1]) 80 | except IndexError: 81 | print("Must include non-admin API key of account that you want to pull via") 82 | return 83 | 84 | env = "https://api.cloudcheckr.com" 85 | 86 | # enter name of account here 87 | account_name = "Account Name Here" 88 | 89 | get_ec2_instances(admin_api_key, env, account_name) 90 | 91 | 92 | if __name__ == '__main__': 93 | main() 94 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project maintainer at support@cloudcheckr.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /Cost/ReloadBillingDataAWS/ReloadBillingDataAWS.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import configparser 4 | 5 | 6 | def main(): 7 | config = configparser.RawConfigParser() 8 | config.read('config.txt') 9 | 10 | api_key = config.get('config', 'APIKey') 11 | api_secret = config.get('config', 'APISecret') 12 | customer_number = config.get('config', 'customerNumber') 13 | month_to_reload = config.get('config', 'monthToReload') 14 | 15 | print("Getting token") 16 | bearer_token = get_access_token("https://auth-us.cloudcheckr.com/auth/connect/token", api_key, api_secret) 17 | 18 | get_all_payer_accounts(customer_number, bearer_token, month_to_reload) 19 | 20 | 21 | def get_all_payer_accounts(customer_number, bearer_token, month_to_reload): 22 | results = [] 23 | print("Getting all accounts") 24 | 25 | url = f"https://api-us.cloudcheckr.com/customer/v1/customers/{customer_number}/accounts?accountTypes=General" 26 | headers = { 27 | 'Accept': 'application/json', 28 | 'Authorization': 'Bearer ' + bearer_token 29 | } 30 | response = requests.get(url, headers=headers) 31 | 32 | account_json = response.json() 33 | results.extend(account_json['items']) 34 | print("Results:", results) 35 | 36 | next_key = account_json.get('pagination', {}).get('nextKey') 37 | while next_key: 38 | print("Running while loop, nextKey detected") 39 | url = f"https://api-us.cloudcheckr.com/customer/v1/customers/{customer_number}/accounts?accountTypes=General&$paginationKey={next_key}" 40 | response_next = requests.get(url, headers=headers) 41 | response_json = response_next.json() 42 | next_key = response_json.get('pagination', {}).get('nextKey') 43 | if next_key: 44 | print("nextKey:", next_key) 45 | results.extend(response_json['items']) 46 | 47 | for item in results: 48 | print("Item:", item) 49 | if item.get("provider") == "AWS" and item.get("providerPaymentType") == 'Payer': 50 | print("This item is an AWS Payer:", item) 51 | legacy_id = item.get('legacyAccountId') 52 | unlock_month(legacy_id, month_to_reload, bearer_token) 53 | reprocess_month(legacy_id, month_to_reload, bearer_token) 54 | 55 | 56 | def get_access_token(url, client_id, client_secret): 57 | response = requests.post( 58 | url, 59 | data={"grant_type": "client_credentials"}, 60 | auth=(client_id, client_secret), 61 | ) 62 | return response.json().get("access_token") 63 | 64 | 65 | def unlock_month(legacy_id, month_to_reload, bearer_token): 66 | url = f"https://api.cloudcheckr.com/api/billing.json/aws_billing_report_unlock_month?access_key=bearer {bearer_token}&use_cc_account_id={legacy_id}" 67 | payload = json.dumps({ 68 | "billing_month": month_to_reload, 69 | "lock_month": "false", 70 | "change_reseller_files": "true" 71 | }) 72 | headers = { 73 | 'Content-Type': 'application/json' 74 | } 75 | 76 | response = requests.post(url, headers=headers, data=payload) 77 | 78 | print(response.text) 79 | 80 | 81 | def reprocess_month(legacy_id, month_to_reload, bearer_token): 82 | url = f"https://api.cloudcheckr.com/api/billing.json/aws_billing_report_reprocess_month?access_key=bearer {bearer_token}&use_cc_account_id={legacy_id}" 83 | payload = json.dumps({ 84 | "billing_month": month_to_reload, 85 | }) 86 | headers = { 87 | 'Content-Type': 'application/json' 88 | } 89 | 90 | response = requests.post(url, headers=headers, data=payload) 91 | 92 | print(response.text) 93 | 94 | 95 | if __name__ == "__main__": 96 | main() 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![CloudCheckr Success Center](media/CloudCheckrDeveloperCommunity.png) 2 | 3 | # Welcome to the CloudCheckr Development Community! 4 | 5 | Hi! Welcome to the CloudCheckr Development community! This is a repository of scripts, tools or otherwise that can help you quickly integrate CloudCheckr using the native **API**. 6 | 7 | If you're new to CloudCheckr and just getting started. Please check out our **Getting Started Guide** on our Success portal: [Lets go!](https://success.cloudcheckr.com/) 8 | 9 | ## What is this? 10 | 11 | This GitHub developer community is a culmination of scripts, tools and otherwise that have been used by CloudCheckr staff and customers to quickly connect internal tools to CloudCheckr OR quickly configure CloudCheckr based on their business needs. 12 | 13 | ## Why are we doing this? 14 | 15 | Over the last few years we have noticed an increasing number of customers integrating CloudCheckr via our API directly into their own internal tools. 16 | 17 | Additionally, we have seen the need to help customers rapidly deploy new accounts, configurations and users into CloudCheckr via the API. 18 | 19 | In order to help expedite this initiative, we created this GitHub repository and compiled a curated number of scripts, tools and other items in order to help jump start a developers work. 20 | 21 | ## How do I use this? 22 | 23 | This is a public GitHub repository, please feel free to fork it or pull down the code directly into your GIT client of choice. 24 | 25 | Content is separated by category as it relates to CloudCheckr as a product and implies how scripts could be used per product module. 26 | 27 | In order to get started with the API and to access your API key, please review the following instructions: https://support.cloudcheckr.com/api-cli-and-setup/ 28 | 29 | The currently published scripts are written in python 3 and use the [requests](http://docs.python-requests.org/en/master/) module for making API calls. In order to run the scripts, you will have to enter in the API key to the command line. The 64 character string is a API key that is used to connect to the CloudCheckr API. Some scripts will have other command line arguments that are written to the command line as well or variables that can be configured in the script such as account name. 30 | 31 | For data processing and analysis the json, [numpy](http://www.numpy.org/), and [pandas](https://pandas.pydata.org/) libraries are used for certain scripts. 32 | 33 | ``` 34 | python get_ec2_instances.py 35 | ``` 36 | 37 | ## Contributing 38 | 39 | This is an open source project and welcomes contributions. Currently all of these scripts are written in python 3 and use the requests library to interact with the CloudCheckr API. However, since the CloudCheckr API is a REST API it can be used with any programming language that can interact with a REST API, so additional programming languages can be used. 40 | 41 | 42 | See our [Contributing Guide](CONTRIBUTING.md) for more details. 43 | 44 | 45 | ## Example use case 46 | 47 | 1. A number of Cloud Resellers and MSPs have their own internal tools to help create a Quarterly Business Review document or dashboard. Using the CloudCheckr API you can pull out a end customers cloud spend data across 1-N accounts as well as their forecast and any custom reporting you have made for them via Advanced Grouping. 48 | 2. An MSP may be onboarding new customers and have created a set number of Budget Alerts and Security Alerts based on their service offering. You can easily script the Alerts via the CloudCheckr API to enable easy onboarding of your customers configuration into the system. 49 | 3. If your security team likes to keep an audit history of system changes, alerts or compliance initiatives within a internal system to your company, you can use the CloudCheckr API to pull this data into your system. Easily pull down Best Practice Checks, Change Monitoring and Total Compliance data points to ingest into an external repository. 50 | -------------------------------------------------------------------------------- /Onboarding/AddGroupPermissions/README.md: -------------------------------------------------------------------------------- 1 | # Use CloudCheckr's API to Add Permissions to Groups 2 | 3 | The purpose of this script is to use the acls that were previously downloaded and add them to groups. 4 | 5 | --- 6 | 7 | ## Steps to Setup Input File 8 | 9 | 1. Navigate to the AddGroupPermissions folder. 10 | 2. In the first column write the environment such as https://api.cloudcheckr.com 11 | 3. In the second column unique name of a group that you want to add a permission to. 12 | 4. In the third column write the name of the account in CloudCheckr that you wish to add permissions for that account to. 13 | 5. Repeat the above for as many groups and accounts that you want to add permissions to. 14 | 6. Each group and account should have its own line. 15 | 7. Make sure the that AwsPermissions.csv, AwsMavPermissions.csv etc files are the permissions that you generated in a previous step. When the program is first downloaded, the will be no files here so the program will not run. You may have to go back to the GetAcls folder and copy the csv files here. 16 | 8. The file names for the permission csv files are hard coded in this program. 17 | 18 | --- 19 | 20 | ## Steps to Add Group Permissions. 21 | 22 | 1. Run the python program add_group_permissions.py. 23 | 2. You must put the admin api key as a command line input. An example is below. 24 | 3. python add_group_permissions.py 0000000000000000000000000000000000000000000000000000000000000000 25 | 4. If this runs as expected, it will ouput the group and accounts that had permissions added to the command line and log. 26 | 27 | --- 28 | 29 | ## How this program works. 30 | 31 | This program will read the list of group permissions for every account type from the Permission csv files using pandas [read_csv](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html). Then it will read the accounts and groups that you want to add permissions for from the groups_perimssions_input.csv file. 32 | 33 | Then it will build a numpy array that links the group names and group ids with [get_groups_v2](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_groups_v2). Group names must be unique because of this. 34 | 35 | It will then loop through all of the accounts that you want to add permissions for and get the account type with [get_account](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_account). Then based on the account type it will connect that to the corresponding permissions list that was imported from the csv file. 36 | 37 | With the group id, acl list, and account name known, it will then use a post request to add permissions with [add_access_control_lists_per_account_per_group](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#add_access_control_lists_per_account_per_group)]. This action will be logged to the command line. 38 | 39 | If an account needs permissions, but there is no corresponding permissions list for that account type it will be skipped and logged. 40 | 41 | --- 42 | 43 | ## CloudCheckr Group ACLs Info 44 | 45 | Every group permission is defined by a particular ACL (access control list). This permission will be unique to the kind of account it is. There are four kinds of accounts Aws Accounts, Aws MAVs, Azure Accounts, and Azure MAVs. 46 | 47 | The access control list is a long string such as 536f7e9a-c15f-4952-a289-e870f3a09930[CC_Delimiter]07ac5ec8-c453-494a-b7ed-469e3090b2b5. This string will correspond to the permission Generic,See List Costs. 48 | 49 | We recommend setting up a template group through the UI and logging in as a test user through that group to see if the permissions align with what you expect. Then downloading the ACLs from this template group to expand to other groups. This way you can decrease how much you directly interact with these ACLs. 50 | 51 | --- 52 | 53 | ## CloudCheckr Group Ids 54 | 55 | Every group will have a unique group id. This will be a UUID number. 56 | 57 | --- 58 | 59 | ## Contact 60 | 61 | Alec Rajeev - Technical Support Engineer - Tier II 62 | alec.rajeev@cloudcheckr.com -------------------------------------------------------------------------------- /Cost/AddCustomCharges/upload_custom_charges.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import json 3 | import requests 4 | import logging 5 | import sys 6 | logging.basicConfig(filename='upload_charges_logging_september.log',level=logging.INFO) 7 | 8 | # python upload_custom_charges.py 0000000000000000000000000000000000000000000000000000000000000000 9 | 10 | def load_custom_charges(custom_charges_file): 11 | 12 | custom_charges_dtype = [("Account", "U12"), 13 | ("Amount", "U36"), 14 | ("startDate", "U10"), 15 | ("endDate", "U10"), 16 | ("description", "U70")] 17 | 18 | custom_charges = np.loadtxt(custom_charges_file, dtype=custom_charges_dtype, delimiter=",", skiprows=1) 19 | print(custom_charges) 20 | logging.info(custom_charges) 21 | print("\n") 22 | logging.info("\n") 23 | 24 | return custom_charges 25 | 26 | 27 | 28 | def add_custom_fixed_charge(env, admin_api_key, startDate, endDate, amount, oneTime, description, account, payer_account_name): 29 | 30 | api_url = env + "api/billing.json/add_custom_billing_charge_fixed" 31 | 32 | fixedChargeData = json.dumps({"startDate": startDate, "endDate": endDate, "amount": amount, "oneTime": oneTime, "description": description, "accounts": [account], "use_account": payer_account_name}) 33 | 34 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = fixedChargeData) 35 | 36 | 37 | if "Id" in r7.json(): 38 | print("Added the custom charge " + description + " with the amount " + amount + " for the AWS Account " + account + " with a start date of " + startDate) 39 | print(r7.json()) 40 | print("") 41 | logging.info("Added the custom charge " + description + " with the amount " + amount + " for the AWS Account " + account + " with a start date of " + startDate) 42 | logging.info(r7.json()) 43 | logging.info("\n") 44 | return r7.json()["Id"] 45 | else: 46 | if (not (description is None)) and (not (account is None)): 47 | print("Custom charge " + description + " for account " + account + " failed") 48 | logging.info("Custom charge " + description + " for account " + account + " failed") 49 | logging.info(r7.json()) 50 | logging.info("\n") 51 | print("\n") 52 | return None 53 | else: 54 | print("Custom charge " + description + " for account " + account + " failed") 55 | logging.info("Custom charge " + description + " for account " + account + " failed") 56 | logging.info(r7.json()) 57 | logging.info("\n") 58 | print("\n") 59 | return None 60 | 61 | def cycle_custom_charges(env, admin_api_key, custom_charges, payerProjectId): 62 | 63 | if np.shape(custom_charges)[0] < 1: 64 | print("Custom Charges file too short") 65 | logging.info("Custom Charges file too short") 66 | return None 67 | charge_ids = np.array([]) 68 | 69 | for i in np.arange(0, np.shape(custom_charges)[0]): 70 | charge_id = None 71 | if np.size(custom_charges[i]) != 5: 72 | charge_id = add_custom_fixed_charge(env, admin_api_key, custom_charges[i][2], custom_charges[i][3], custom_charges[i][1], "True", custom_charges[i][4], custom_charges[i][0], payerProjectId) 73 | else: 74 | print("Did NOT add custom charge of line " + str(i)) 75 | logging.info("Did NOT add custom charge of line " + str(i)) 76 | if not(charge_id is None): 77 | charge_ids = np.append(charge_ids, charge_id) 78 | 79 | return charge_ids 80 | 81 | 82 | def main(): 83 | try: 84 | admin_api_key = str(sys.argv[1]) 85 | except IndexError: 86 | print("Must admin_api_key") 87 | return 88 | 89 | env = "https://api.cloudcheckr.com/" 90 | 91 | payer_account_name = "Payer Master Account" 92 | 93 | custom_charges_file = "custom_charges.csv" 94 | 95 | custom_charges = load_custom_charges(custom_charges_file) 96 | 97 | charge_ids = cycle_custom_charges(env, admin_api_key, custom_charges, payer_account_name) 98 | 99 | output_file = "added_charges.csv" 100 | 101 | np.savetxt(output_file, charge_ids, delimiter=",", newline="\n", fmt="%i") 102 | 103 | print("Saved custom charge id's added to " + output_file) 104 | logging.info("Saved custom charge id's added to " + output_file) 105 | 106 | 107 | 108 | if __name__ == "__main__": 109 | main() -------------------------------------------------------------------------------- /Onboarding/DefaultAccountFamily/default_account_family.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import sys 4 | import logging 5 | logging.basicConfig(filename='logging_for_default_account_family.log',level=logging.INFO) 6 | 7 | """ 8 | This python script is used to add all unmapped accounts to a single account family 9 | python default_account_family.py admin_api_key project_id account_family 10 | (example) python3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5 "183698509299 (Aaron Gettings)" 11 | """ 12 | 13 | def log_information(log_string): 14 | logging.info(log_string) 15 | print(log_string) 16 | 17 | 18 | def get_accounts(admin_api_key, env, project_id, default_account_family): 19 | """ 20 | Uses admin API key to get account data for modify_account_family API call 21 | """ 22 | 23 | half_url = f"{env}/api/billing.json/get_account_family_v2" 24 | api_parameters = {"use_cc_account_id": project_id} 25 | resp = requests.get(half_url, params=api_parameters, headers = {"access_key": admin_api_key}) 26 | 27 | account_families = [] 28 | existing_accounts = [] 29 | unmapped_accounts = [] 30 | accounts = [] 31 | account_string = [] 32 | 33 | if "Code" in resp.json(): 34 | account_families = resp.json()["AccountFamilies"] 35 | for account_familiy in account_families: 36 | if account_familiy["Name"] == default_account_family: 37 | existing_accounts = account_familiy["Accounts"] 38 | unmapped_accounts = resp.json()["UnmappedAccounts"] 39 | accounts = existing_accounts + unmapped_accounts 40 | for account in accounts: 41 | account_string.append(account.split(" ")[0]) 42 | log_information("Obtained account data") 43 | else: 44 | log_information("Failed to obtain account data") 45 | return 46 | 47 | return ",".join(account_string) 48 | 49 | 50 | def modify_account_family(admin_api_key, env, project_id, default_account_family, accounts): 51 | """ 52 | Uses admin API key to add all unmapped accounts to default account family 53 | """ 54 | 55 | half_url = f"{env}/api/billing.json/modify_account_family" 56 | api_parameters = {"use_cc_account_id": project_id, "name": default_account_family, "accounts": accounts} 57 | resp = requests.post(half_url, data=json.dumps(api_parameters), headers = {"Content-type": "application/json", "access_key": admin_api_key}) 58 | 59 | if "Code" in resp.json(): 60 | log_information(f"Modified account family: {default_account_family}") 61 | else: 62 | log_information(f"Falied to modifify account family: {default_account_family}") 63 | 64 | 65 | def validate_env(env): 66 | """ 67 | Validates enviroment. By default, it checks for api, eu, au, gov and qa. 68 | If you are using a standalone environment, then you must add it to the environments list 69 | """ 70 | 71 | enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 72 | 73 | if env not in enviroments: 74 | log_information(f"The environment {env} is not valid. If this is a standalone environment, please add the url to the validate_env function.") 75 | return 76 | 77 | 78 | def main(): 79 | try: 80 | admin_api_key = str(sys.argv[1]) 81 | except IndexError: 82 | log_information("Must include admin API key") 83 | return 84 | 85 | try: 86 | project_id = str(sys.argv[2]) 87 | except IndexError: 88 | log_information("Must include project id") 89 | return 90 | 91 | try: 92 | account_family = str(sys.argv[3]) 93 | except IndexError: 94 | log_information("Must include default account family") 95 | return 96 | 97 | env = "https://api.cloudcheckr.com" 98 | validate_env(env) 99 | 100 | account_string = get_accounts(admin_api_key, env, project_id, account_family) 101 | modify_account_family(admin_api_key, env, project_id, account_family, account_string) 102 | 103 | 104 | if __name__ == '__main__': 105 | main() -------------------------------------------------------------------------------- /Onboarding/AddUsers/logging_for_adding_users.log: -------------------------------------------------------------------------------- 1 | INFO:root: Environment Email \ 2 | 0 https://api.cloudcheckr.com alec.rajeev+groups111@cloudcheckr.com 3 | 1 https://api.cloudcheckr.com alec.rajeev+groups112@cloudcheckr.com 4 | 2 https://api.cloudcheckr.com alec.rajeev+groups113@cloudcheckr.com 5 | 3 https://api.cloudcheckr.com david.barnard+ro@cloudcheckr.com 6 | 4 https://api.cloudcheckr.com alec.rajeev@cloudcheckr.com 7 | 5 https://api.cloudcheckr.com alec.rajeev+groups112@cloudcheckr.com 8 | 6 https://api.cloudcheckr.com alec.rajeev+groups115@cloudcheckr.com 9 | 10 | Role 11 | 0 BasicUser 12 | 1 BasicUser 13 | 2 BasicUser 14 | 3 BasicUser 15 | 4 BasicUser 16 | 5 BasicUser 17 | 6 BasiccUser 18 | INFO:root:Started adding users 19 | INFO:root:Added the user alec.rajeev+groups111@cloudcheckr.com with the role BasicUser 20 | INFO:root:{'CreationStatuses': ['Created new user with email: alec.rajeev+groups111@cloudcheckr.com']} 21 | INFO:root:Added the user alec.rajeev+groups112@cloudcheckr.com with the role BasicUser 22 | INFO:root:{'CreationStatuses': ['Created new user with email: alec.rajeev+groups112@cloudcheckr.com']} 23 | INFO:root:Added the user alec.rajeev+groups113@cloudcheckr.com with the role BasicUser 24 | INFO:root:{'CreationStatuses': ['Created new user with email: alec.rajeev+groups113@cloudcheckr.com']} 25 | INFO:root:The user david.barnard+ro@cloudcheckr.com already exists in this account, so it was not added 26 | INFO:root:Failed to add the user alec.rajeev@cloudcheckr.com 27 | INFO:root:{'Message': 'The request is invalid.', 'ModelState': {'ErrorCode': ['BadRequest'], 'ErrorIdentity': ['6367455506069373376548044e-6f63-4273-acee-cacf0179c139'], 'ErrorMessage': ['A user with provided email already exists.']}} 28 | INFO:root:The user alec.rajeev+groups112@cloudcheckr.com already exists in this account, so it was not added 29 | INFO:root:The user alec.rajeev+groups115@cloudcheckr.com was not added because the role BasiccUser does not exist. 30 | INFO:root:Finished adding users 31 | INFO:root: Environment Email \ 32 | 0 https://api.cloudcheckr.com alec.rajeev+groups115@cloudcheckr.com 33 | 1 https://api.cloudcheckr.com alec.rajeev+groups116@cloudcheckr.com 34 | 2 https://api.cloudcheckr.com alec.rajeev+groups117@cloudcheckr.com 35 | 3 https://api.cloudcheckr.com david.barnard+ro@cloudcheckr.com 36 | 4 https://api.cloudcheckr.com alec.rajeev+groups112@cloudcheckr.com 37 | 5 https://api.cloudcheckr.com alec.rajeev+groups111@cloudcheckr.com 38 | 39 | Role 40 | 0 BasicUser 41 | 1 BasicUser 42 | 2 BasicUser 43 | 3 BasicUser 44 | 4 BasicUser 45 | 5 BasicUser 46 | INFO:root:Started adding users 47 | INFO:root:Added the user alec.rajeev+groups115@cloudcheckr.com with the role BasicUser 48 | INFO:root:{'CreationStatuses': ['Created new user with email: alec.rajeev+groups115@cloudcheckr.com']} 49 | INFO:root:Added the user alec.rajeev+groups116@cloudcheckr.com with the role BasicUser 50 | INFO:root:{'CreationStatuses': ['Created new user with email: alec.rajeev+groups116@cloudcheckr.com']} 51 | INFO:root:Added the user alec.rajeev+groups117@cloudcheckr.com with the role BasicUser 52 | INFO:root:{'CreationStatuses': ['Created new user with email: alec.rajeev+groups117@cloudcheckr.com']} 53 | INFO:root:The user david.barnard+ro@cloudcheckr.com already exists in this account, so it was not added 54 | INFO:root:The user alec.rajeev+groups112@cloudcheckr.com already exists in this account, so it was not added 55 | INFO:root:The user alec.rajeev+groups111@cloudcheckr.com already exists in this account, so it was not added 56 | INFO:root:Finished adding users 57 | INFO:root:Started adding users 58 | INFO:root:Added the user alec.rajeev+groupsmilan@cloudcheckr.com with the role BasicUser 59 | INFO:root:{'CreationStatuses': ['Created new user with email: alec.rajeev+groupsmilan@cloudcheckr.com']} 60 | INFO:root:The user alec.rajeev+groupsmilan@cloudcheckr.com already exists in this account, so it was not added 61 | INFO:root:The user alec.rajeev+groupsmilan@cloudcheckr.com already exists in this account, so it was not added 62 | INFO:root:Finished adding users 63 | -------------------------------------------------------------------------------- /Onboarding/AddAwsAccounts/README.md: -------------------------------------------------------------------------------- 1 | **Onboard Accounts with CloudFormation and CloudCheckr API** 2 | 3 | --- 4 | 5 | ## Steps to Run 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install boto3, numpy, and requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html 10 | 3. Create an role with the permissions to create cloud formation stacks and IAM roles/policies. https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html 11 | 4. Create an IAM User that can assume that role. 12 | 5. Create an access key from that user and add to a profile on your local machine. 13 | 6. Create a new local profile for that role and specify that user as what should be used to assume the role. This profile will have a name that is an input value to the script. https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html (alternatively you can name it something else, you just have to edit the create_iam_role_from_cloud_formation() function to have to new profile name) 14 | 7. Log in to CloudCheckr and create an Admin API access key. 15 | 8. Run python add_account.py 16 | The profile_name is the name of the profile that is saved to the local machine. This profile should either be a user or a role that has IAM Admin permissions and create CloudFormation stack permissions. 17 | The name CloudCheckr admin api key is a 64 character string. 18 | The CloudCheckr Account name is the name of the new account in CloudCheckr. This account name should be unique. 19 | The cloudtrail-bucket-name is the name of the s3 bucket with cloudtrail data. If this is blank, then no cloudtrail data will be added. 20 | The billing-bucket-name is the name of the s3 bucket with the DBR. For payee accounts this can be left blank. 21 | The cur-bucket is the name of the s3 bucket with the CUR. For payee accounts this can be left blank. 22 | The bucket names are optional, but the admin api key and account name are required. 23 | 9. Output will log the actions done. 24 | 25 | --- 26 | 27 | ## How the program works 28 | 29 | CloudCheckr has an admin api key that can be used to assist in onboarding accounts to CloudCheckr. 30 | 31 | The first step is to use [add_account_v3](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#add_account_v3) to add an AWS account to CloudCheckr. This will be account will be an account with empty credentials and will return an external id for future use. 32 | 33 | The second step is to use the CloudCheckr [CloudFormation Stack](https://support.cloudcheckr.com/getting-started-with-cloudcheckr/complete-iam-policy/) to create a cloudformation stack. This stack will create an IAM role with the external id generated in the previous step. Then the stack will create the various IAM Policies for each service based on the input data. It will create policies that give specific permissions for s3 bucket access if there is an input for it. This can be used to limit permissions to specific buckets with DBR or CloudTrail data. Then these policies will be attached to the previously created role. It usually takes around 30 seconds for this to complete and will return a cross account role. The boto3 API calls [create_stack](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.create_stack) and [describe_stacks](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.describe_stacks) are used for this. 34 | 35 | The third step is to use [edit_credential](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#edit_credential) to add the cross-account role to CloudCheckr. 36 | 37 | --- 38 | 39 | ## Assumptions 40 | 41 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 181 if required. 42 | 2. The machine that is running the computer has an AWS credentials profile. This profile is an input to the script. This user or role has the permissions to create stacks and create IAM roles/policies. 43 | 3. Program only allows for adding a CloudTrail bucket, but not a DBR bucket. If you want to add a DBR bucket, but not a CloudTrail bucket you can adjust the inputs around lines 161 to 172 to account for this or just use an example bucket name such as cloudtrailbucket. 44 | 4. These accounts are only commercial accounts. GovCloud accounts will require adding them through the UI. -------------------------------------------------------------------------------- /Onboarding/UserMigration/reset_users_and_groups.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import sys 4 | import numpy as np 5 | 6 | # python3 reset_users_and_groups.py qa 0000000000000000000000000000000000000000000000000000000000000000 7 | # used to reset the second environment if you would like to start fresh 8 | 9 | 10 | def get_groups(env, admin_api_key): 11 | api_url = "https://" + env + ".cloudcheckr.com/api/account.json/get_groups_v2" 12 | 13 | r1 = requests.get(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}) 14 | 15 | if ('ErrorCode' in r1.json()): 16 | if (r1.json()['ErrorCode'] == "NotFound"): 17 | print("No Groups") 18 | return None 19 | # print(r1.json()) 20 | # print(r1.json()['Groups']) 21 | return r1.json()['Groups'] 22 | 23 | def delete_group(env, admin_api_key, group_id): 24 | api_url = "https://" + env + ".cloudcheckr.com/api/account.json/delete_group" 25 | r2 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = json.dumps({"group_id": group_id})) 26 | 27 | def delete_groups(env, admin_api_key, groups): 28 | if (groups is None): 29 | return 30 | for i in np.arange(0, np.size(groups)): 31 | delete_group(env, admin_api_key, groups[i]["Id"]) 32 | print("Deleted Group " + groups[i]["Id"]) 33 | 34 | def get_users(env, admin_api_key): 35 | api_url = "https://" + env + ".cloudcheckr.com/api/account.json/get_users_v2" 36 | r1 = requests.get(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}) 37 | users = r1.json()['user_permissions'] 38 | 39 | return users 40 | 41 | def delete_user(env, admin_api_key, user_email): 42 | api_url = "https://" + env + ".cloudcheckr.com/api/account.json/remove_user" 43 | 44 | # print(user_email) 45 | r2 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = json.dumps({"email": user_email})) 46 | # print(r2.json()) 47 | if ('ModelState' in r2.json()): 48 | print(user_email + " failed to be deleted") 49 | print(r2.json()) 50 | else: 51 | print(user_email + " was deleted") 52 | 53 | def add_user(env, admin_api_key, env_type, email, role, group_name): 54 | """ 55 | Adds a user to the new environment. Will only add to a gorup if the user is in a group. 56 | Will add functionality around logon rules later. 57 | Can't use add_users because users in the same group could have different roles. 58 | """ 59 | 60 | api_url = "https://" + env + ".cloudcheckr.com/api/account.json/add_user" 61 | 62 | r7 = None 63 | 64 | # email = get_corrected_email(email, env_type) 65 | 66 | if (group_name is None): 67 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = json.dumps({"email": email, "user_role": role})) 68 | else: 69 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = json.dumps({"email": email, "user_role": role, "group": group_name})) 70 | 71 | if ("Message" in r7.json()): 72 | print("Failed to create new user " + email) 73 | print(r7.json()) 74 | else: 75 | if ("CreationStatuses" in r7.json()): 76 | if (group_name is None): 77 | print("Created the user " + email) 78 | print(r7.json()) 79 | else: 80 | print("Created the user " + email + " in the group" + group_name) 81 | print(r7.json()) 82 | else: 83 | print("Failed to create user " + email) 84 | print(r7.json()) 85 | return email 86 | 87 | def delete_users(env, admin_api_key, users): 88 | if (users is None): 89 | print("no users") 90 | return 91 | for i in np.arange(0, np.shape(users)[0]): 92 | delete_user(env, admin_api_key, users[i]["email"]) 93 | 94 | def main(): 95 | print("Reset Groups and Users\n") 96 | env = sys.argv[1] 97 | admin_api_key = sys.argv[2] 98 | groups = get_groups(env, admin_api_key) 99 | delete_groups(env, admin_api_key, groups) 100 | users = get_users(env, admin_api_key) 101 | delete_users(env, admin_api_key, users) 102 | # print("\n") 103 | # adds a simple admin, because later when you try to add a user without an Admin, it throws an error 104 | add_user(env, admin_api_key, 1, "example2@example.com", "Administrator", None) 105 | 106 | if __name__ == '__main__': 107 | main() -------------------------------------------------------------------------------- /Onboarding/AddAzureAccounts/README.md: -------------------------------------------------------------------------------- 1 | **Onboard Azure Accounts with the CloudCheckr API** 2 | 3 | --- 4 | 5 | ## Steps to Setup Environment 6 | 7 | 8 | 1. Install python 3. https://www.python.org/downloads/release/python-365/ 9 | 2. Install requests python libraries with pip. https://github.com/boto/boto3, http://docs.python-requests.org/en/master/user/install/, https://docs.scipy.org/doc/numpy-1.15.1/user/install.html 10 | 11 | --- 12 | 13 | ## Steps to Setup in Azure 14 | 15 | 16 | 1. Get the Azure Directory Id. (Part 1 through 4 of Step 1 here: [Configure Azure Subscription](https://success.cloudcheckr.com/article/lh39ppglft-configure-a-subscription-account-onboarding)). This Azure Directory Id will generally be the same for all subscriptions that are under a single Parent Account. The Parent account is the CSP or EA that contains the cost data. 17 | 2. Create and register an application in Azure. This application should have a specific purpose of being used for credentials with CloudCheckr. Then create the Azure Application secret. This only has to be done once per tenant. (Part 5 through 12 of Step 1 here: [Configure Azure Subscription](https://success.cloudcheckr.com/article/lh39ppglft-configure-a-subscription-account-onboarding)) 18 | 3. Add a Role Assignment for the application to a subscription. This part has to be done for every subscription that is planning to be 19 | added to CloudCheckr. (Step 2 here: [Configure Azure Subscription](https://success.cloudcheckr.com/article/lh39ppglft-configure-a-subscription-account-onboarding)) 20 | 21 | Note: This part has to be done for each subscription. A potential improvement is to automate this step using the global admin. 22 | [elevate-access-global](https://docs.microsoft.com/en-us/azure/role-based-access-control/elevate-access-global-admin) 23 | 24 | The global admin credentials can likely be used to automatically add the role assignment to each subscription using this Azure Role Assignment API call. 25 | [role-assignments-rest](https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-rest) 26 | 27 | 4. Get the Subscription Id. The subscription id will be different for every subscription. (This is Parts 13 through 16 of Step 1 here: [Configure Azure Subscription](https://success.cloudcheckr.com/article/lh39ppglft-configure-a-subscription-account-onboarding)) 28 | 29 | --- 30 | 31 | ## Steps to Run Script 32 | 33 | 34 | 1. Create a CloudCheckr Admin API key. This can be found by logging in to the Core CloudCheckr application. Then navigate to Admin Functions -> Admin API Key. Then click create an Admin API Key. 35 | 2. Determine the name of the CloudCheckr Account. This name will represent a subscription. 36 | 3. Gather the Azure Directory Id, Azure Application Id, Azure Application Secret, and Azure Subscription Id from the above. 37 | 4. Run the below. 38 | 39 | ``` 40 | python add_azure_account.py 41 | ``` 42 | * The CloudCheckr admin api key is a 64 character string. 43 | * The CloudCheckr Account name is the name of the new account in CloudCheckr. 44 | * The azure-active-directory-id is the GUID directory id. This will generally be the same for all subscriptions that have the same parent. (Parent being their associated CSP or EA account that contains cost data) 45 | * The azure-application-id is the GUID id of the application that was created previously. It can be re-used for multiple subscriptions, but have to give the application permissions in each subscription. 46 | * The azure-application-secret is the secret key that was created previously. This is shown only once when generating the key. It can last 1 year, 2 years, or forever. 47 | * The azure-subscription-id is the GUID that corresponds to the id of the subscription. This subscription will be different for every account that is added to CloudCheckr. 48 | 9. Output will log the actions done. 49 | 50 | --- 51 | 52 | ## How the program works 53 | 54 | 55 | CloudCheckr has an admin api key that can be used to assist in onboarding accounts to CloudCheckr. The python program will take the input names and keys and preform the [add_azure_inventory_account](https://success.cloudcheckr.com/article/eem9bajrak-api-reference-guide-azure#addazureinventoryaccount) API call. This will create a new account in CloudCheckr and it will populate the account with the specified Azure Credentials. 56 | 57 | --- 58 | 59 | ## Assumptions 60 | 61 | 62 | 1. The environment https://api.cloudcheckr.com is being used. This can be adjusted on line 73 if required. 63 | 2. The program can use python 3 and the requests library. 64 | 3. The Azure application has already been created, registered, and been granted the Reader role in the required Azure subscription. 65 | 4. This program should be run once per subscription. 66 | -------------------------------------------------------------------------------- /Cost/AddCostAlerts/add_budget_alerts.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import numpy as np 4 | import sys 5 | import logging 6 | logging.basicConfig(filename='logging_for_add_cost_alerts.log',level=logging.INFO) 7 | 8 | """ 9 | This python script is used to add cost alerts to all non mav AWS accounts 10 | python3 add_cost_alerts.py 0000000000000000000000000000000000000000000000000000000000000000 11 | """ 12 | 13 | def log_information(log_string): 14 | logging.info(log_string) 15 | print(log_string) 16 | 17 | 18 | def get_accounts(admin_api_key, env): 19 | 20 | if check_invalid_env(env): 21 | return 22 | 23 | api_url = env + "/api/account.json/get_accounts_v4" 24 | 25 | r7 = requests.get(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}) 26 | 27 | # print(r7.json()) 28 | 29 | accounts_list = [] 30 | 31 | if "accounts_and_users" in r7.json(): 32 | accounts_and_users = r7.json()["accounts_and_users"] 33 | for i in np.arange(0, np.shape(accounts_and_users)[0]): 34 | if "cc_account_id" in accounts_and_users[i]: 35 | accounts_list.append(accounts_and_users[i]["cc_account_id"]) 36 | 37 | return accounts_list 38 | 39 | def check_aws(admin_api_key, env, cc_account_id): 40 | """ 41 | Checks if an account is an AWS Account with get_account API call 42 | """ 43 | 44 | api_url = env + "/api/account.json/get_account" 45 | 46 | get_account_info = json.dumps({"account_id": cc_account_id}) 47 | 48 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = get_account_info) 49 | 50 | # checks for AWS and non-mav 51 | if "Provider" in r7.json() and "Type" in r7.json(): 52 | if r7.json()["Provider"] == "Amazon Web Services" and r7.json()["Type"] == "General": 53 | return True 54 | return False 55 | 56 | 57 | def add_cost_alert(admin_api_key, env, cc_account_id, alert_name, emails, budget, percent_of_budget, budget_period): 58 | 59 | if check_invalid_env(env): 60 | return None 61 | 62 | api_url = env + "/api/alert.json/add_cost_alert" 63 | 64 | add_cost_alert_info = json.dumps({"use_cc_account_id": cc_account_id, "alert_name": alert_name, "emails": emails, "budget": budget, "percent_of_budget": percent_of_budget, "budget_period": budget_period}) 65 | 66 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = add_cost_alert_info) 67 | 68 | if "Code" in r7.json(): 69 | log_information("Successfully added the cost alert " + alert_name + " to the CloudCheckr account with id " + str(cc_account_id)) 70 | log_information(r7.json()) 71 | log_information("") 72 | else: 73 | log_information("Unable to add cost alert") 74 | log_information(r7.json()) 75 | 76 | 77 | def cycle_accounts(admin_api_key, env, accounts_list, alert_name, emails, budget, percent_of_budget, budget_period): 78 | log_information("Started adding cost alerts") 79 | 80 | for i in np.arange(0, np.shape(accounts_list)[0]): 81 | if check_aws(admin_api_key, env, accounts_list[i]): 82 | add_cost_alert(admin_api_key, env, accounts_list[i], alert_name, emails, budget, percent_of_budget, budget_period) 83 | 84 | log_information("Finished adding cost alerts") 85 | 86 | def check_invalid_env(env): 87 | """ 88 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 89 | If you are using a standalone environment, then you MUST add that to this function 90 | """ 91 | 92 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 93 | 94 | 95 | if not(env in Enviroments): 96 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 97 | return True 98 | return False 99 | 100 | 101 | def main(): 102 | try: 103 | admin_api_key = str(sys.argv[1]) 104 | except IndexError: 105 | print("Must admin_api_key") 106 | return 107 | 108 | env = "https://api.cloudcheckr.com" 109 | 110 | # add emails here, can add multiple by separating by comma 111 | emails = "alec.rajeev+addcostalerttest3@cloudcheckr.com" 112 | 113 | # add alert name here 114 | alert_name = "Onboarding Alert Api" 115 | 116 | # budget amount here 117 | budget = "100" 118 | 119 | # percet of budget here 120 | percent_of_budget = "75" 121 | 122 | # budget period here 123 | budget_period = "monthly" 124 | 125 | accounts_list = get_accounts(admin_api_key, env) 126 | 127 | if accounts_list is None: 128 | return 129 | 130 | cycle_accounts(admin_api_key, env, accounts_list, alert_name, emails, budget, percent_of_budget, budget_period) 131 | 132 | 133 | if __name__ == '__main__': 134 | main() 135 | -------------------------------------------------------------------------------- /Onboarding/GetGroupAcls/README.md: -------------------------------------------------------------------------------- 1 | # Use CloudCheckr's API to Download Example Acls 2 | 3 | The purpose of this script is to download example Acls that will be used to create groups in the future. 4 | 5 | --- 6 | 7 | ## Steps to Setup Group Permissions Template 8 | 9 | 10 | 1. Create a group that will act as a permission template through the user-interface. Name this group Permission Template. 11 | 2. Add example permissions for each of the four account types that you with to have example permissions for. (Aws Account, Aws MAV, Azure Account, and Azure MAV). Only add one account of each type. Using multiple accounts of the same type will result in the first account being used and the later ones being skipped for example permissions. 12 | 3. Create a test user through the user-interface. 13 | 4. Assign this test user to this group Permission Template. 14 | 5. Log in as this user and verify that the permissions correspond to what you expect. Log back in as an Admin and make any adjustements that you need. 15 | 6. Once you have verified that the permissions are what you want proceed on to the next step. 16 | 17 | 18 | --- 19 | 20 | ## Steps to Download Example Acls. 21 | 22 | 1. Navigate to the GetAcls folder. 23 | 2. Delete any example permission csv files that were previously created such as AwsMavPermissions.csv. These are released for reference as an example, but should not be used unless you are just testing things. 24 | 3. Open up the permission_template_input.csv file. This will be a csv file that will be used for example input. 25 | 4. In the fist column put the environment, such as https://api.cloudcheckr.com. 26 | 5. In the second column put the name of the group that was created above. We recommend calling that group Permission Template. This file should only have one line besides the headers. 27 | 6. Run the python program get_access_control_list_per_group.py. 28 | 7. You must put the admin api key as a command line input. An example is below. 29 | 8. python get_access_control_list_per_group.py 0000000000000000000000000000000000000000000000000000000000000000 30 | 9. If this runs as expected, it will ouput permission files such as AwsPermissions.csv. 31 | 10. Copy this permissions file to the folder AddGroupPermissions. Overwrite and delete the old group permissions files. 32 | 33 | 34 | --- 35 | 36 | ## How this program works. 37 | 38 | This program will read the name of group permission template from the input csv file using pandas [read_csv](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html). This group name must be unique because of this. The group id will be pulled with a post request using [get_groups_v2](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_groups_v2) and the group name as an input. 39 | 40 | Using the group id, it will pull the CloudCheckr name for each of the four account types using [get_accounts_by_group](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_accounts_by_group). This will return the four account names for each account type in the group. If there are multiple account types in the group, only the first one returned will be used. 41 | 42 | While keeping track of the account type, the group id and CloudCheckr account name will be used to find the group acls for the corresponding account type from the template. A post request with [get_access_control_list_per_group](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_access_control_list_per_group) will be used. This will pull the acls from the template. 43 | 44 | For additional transparency to the end-user, the [get_access_control_list](https://support.cloudcheckr.com/cloudcheckr-api-userguide/cloudcheckr-admin-api-reference-guide/#get_access_control_list) will be called once to get all of the access control lists in CloudCheckr and put in a numpy array. Then using numpy's [where](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.where.html) function, the previously downloaded access control lists will be matched to a human readable permission name and section. 45 | 46 | Then for each account type, a csv file will be generated called AwsPermissions.csv, AwsMavPermissions.csv etc. These csv files should be copied to the AddGroupPermissions folder for future use. 47 | 48 | --- 49 | 50 | ## CloudCheckr Group ACLs Info 51 | 52 | Every group permission is defined by a particular ACL (access control list). This permission will be unique to the kind of account it is. There are four kinds of accounts Aws Accounts, Aws MAVs, Azure Accounts, and Azure MAVs. 53 | 54 | The access control list is a long string such as 536f7e9a-c15f-4952-a289-e870f3a09930[CC_Delimiter]07ac5ec8-c453-494a-b7ed-469e3090b2b5. This string will correspond to the permission Generic,See List Costs. 55 | 56 | We recommend setting up a template group through the UI and logging in as a test user through that group to see if the permissions align with what you expect. Then downloading the ACLs from this template group to expand to other groups. This way you can decrease how much you directly interact with these ACLs. 57 | 58 | --- 59 | 60 | ## Contact 61 | 62 | Alec Rajeev - Technical Support Engineer - Tier II 63 | alec.rajeev@cloudcheckr.com -------------------------------------------------------------------------------- /Onboarding/README.md: -------------------------------------------------------------------------------- 1 | # Use CloudCheckr's API to Onboard Users and Groups 2 | 3 | The purpose of this script is to provide a process for creating users and groups with the API without having to directly interact with user ids or group ids. All of the required information is contianed in the csv input files. 4 | 5 | --- 6 | 7 | ## Steps to Create Users and Groups 8 | 9 | 10 | 1. Create a group that will act as a permission template through the user-interface. 11 | 2. Run the python script GetAcls/get_access_control_list_per_group.py to download the permissions of the permission template. Each account type will have its own set of permissions. There are four account types Aws Account, Aws MAV, Azure Account, and Azure Mav. This will export up to four csv files on permissions. These files should be copied to the AddGroupPermissions folder. 12 | 3. Run the python script CreateGroups/create_groups.py to create the groups. This python script will first check if there are duplicate groups and stop running if there are. 13 | 4. Run the python script in AddGroupPermissions/add_group_permissions.py to add permissions to the groups that were created. 14 | 5. Run the python script in AddUsers/add_users.py to add users to CloudCheckr. 15 | 6. Run the python script in AddUsersToGroups/add_users_to_groups.py to add users to groups. 16 | 17 | 18 | --- 19 | 20 | ## How to Create an Admin API Key 21 | 22 | 1. Log in as an admin user through the UI. 23 | 2. Go to Admin Functions on the upper right hand corner and click Admin Api Key. 24 | 3. Click create admin key. 25 | 26 | 27 | --- 28 | 29 | ## How to edit the input csv files 30 | 31 | THe CloudCheckr API for users and groups has numerous places where it requires UUID strings that correspond to users or groups. By using this program and the associated csv files, you can erase the need for manually downloading these as this program will find the UUID based on the group name. 32 | 33 | 1. Navigate to the folder corresponding to the program that you want. 34 | 2. The first column will always be the environment. In most cases this will be "https://api.cloudcheckr.com". 35 | 3. The following columns will be the user or group names. 36 | 37 | --- 38 | 39 | ## How to run a python program 40 | 41 | 1. All of the python programs can be run through the command line. They will have the name of the input csv file hard coded in. The input csv file should be editted and updated before running the python program. 42 | 2. The python version used is python 3.6.5. The python libraries used are logging, numpy, pandas, and requests. These can be installed with pip. 43 | 3. You should navigate to the python program and run python script_name.py 44 | 4. The Admin Api Key will be a 64 character string that will be generated by CloudCheckr. 45 | 46 | --- 47 | 48 | ## How to add a new environment such as a SelfHosted version of CloudCheckr 49 | 50 | Most customers will use either api, eu, or au for the environment. If you use are using a custom environment, then this should be added. This program will check if the environment is valid before running, so if a custom environment is used it should be added to the program. 51 | 52 | Every individual program will have a function called check_invalid_env. This should be editted to include the new environment such as https://selfhosted.cloudcheckr.com. 53 | 54 | --- 55 | 56 | ## Duplicate Groups Check 57 | 58 | In the past, Cloudcheckr has allowed for two groups to have the same name. Improved name validation was added to prevent users from creating duplicate group names with the API or the UI. Some customers still have two groups with the same name and they will continue to work. However before any change or update to the groups can be put made, we recommend re-naming groups to remove the duplicate group names. 59 | 60 | This program will check if there are duplicate group names and prevent any further action until duplicate group names have been removed. This is because there are many places were unique group names are used to identify groups in this program. 61 | 62 | --- 63 | 64 | ## Logging 65 | 66 | Every update to CloudCheckr in this program will be done with a post request to the CloudCheckr API. This action will be logged in two places. The first is to the command line with python's native print statements. The second is to a log file that uses python's native log. 67 | 68 | This program will include example logs when it is first downloaded as a reference. These should be cleared out if you want to start fresh. 69 | 70 | --- 71 | 72 | ## CloudCheckr Group ACLs Info 73 | 74 | Every group permission is defined by a particular ACL (access control list). This permission will be unique to the kind of account it is. There are four kinds of accounts Aws Accounts, Aws MAVs, Azure Accounts, and Azure MAVs. 75 | 76 | The access control list is a long string such as 536f7e9a-c15f-4952-a289-e870f3a09930[CC_Delimiter]07ac5ec8-c453-494a-b7ed-469e3090b2b5. This string will correspond to the permission Generic,See List Costs. 77 | 78 | We recommend setting up a template group through the UI and logging in as a test user through that group to see if the permissions align with what you expect. Then downloading the ACLs from this template group to expand to other groups. This way you can decrease how much you directly interact with these ACLs. -------------------------------------------------------------------------------- /Cost/AddSavedFilters/add_saved_filters.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import numpy as np 4 | import sys 5 | import logging 6 | logging.basicConfig(filename='logging_for_add_saved_filter.log',level=logging.INFO) 7 | 8 | """ 9 | This python script is used to add cost alerts to all non mav AWS accounts 10 | python3 add_saved_filter.py 0000000000000000000000000000000000000000000000000000000000000000 11 | """ 12 | 13 | def log_information(log_string): 14 | logging.info(log_string) 15 | print(log_string) 16 | 17 | 18 | def get_accounts(admin_api_key, env): 19 | 20 | if check_invalid_env(env): 21 | return 22 | 23 | api_url = env + "/api/account.json/get_accounts_v4" 24 | 25 | r7 = requests.get(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}) 26 | 27 | # print(r7.json()) 28 | 29 | accounts_list = [] 30 | 31 | if "accounts_and_users" in r7.json(): 32 | accounts_and_users = r7.json()["accounts_and_users"] 33 | for i in np.arange(0, np.shape(accounts_and_users)[0]): 34 | if "cc_account_id" in accounts_and_users[i]: 35 | accounts_list.append(accounts_and_users[i]["cc_account_id"]) 36 | 37 | return accounts_list 38 | 39 | def check_aws(admin_api_key, env, cc_account_id): 40 | """ 41 | Checks if an account is an AWS Account with get_account API call 42 | """ 43 | 44 | api_url = env + "/api/account.json/get_account" 45 | 46 | get_account_info = json.dumps({"account_id": cc_account_id}) 47 | 48 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = get_account_info) 49 | 50 | # checks for AWS (works for mav and non-mav) 51 | if "Provider" in r7.json(): 52 | if r7.json()["Provider"] == "Amazon Web Services": 53 | return True 54 | return False 55 | 56 | 57 | def add_saved_filter(admin_api_key, env, cc_account_id, saved_filter_name, emails, group_by, cost_type, include_usage_quantity, include_zero_costs): 58 | 59 | if check_invalid_env(env): 60 | return None 61 | 62 | api_url = env + "/api/billing.json/create_detailed_billing_grouped_filter_v2" 63 | 64 | add_saved_filter_info = json.dumps({"use_cc_account_id": cc_account_id, "filter_name": saved_filter_name, "emails": emails, "group_by": group_by, "cost_type": cost_type, "include_usage_quantity": include_usage_quantity, "include_zero_costs": include_zero_costs}) 65 | 66 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = add_saved_filter_info) 67 | 68 | if "Code" in r7.json(): 69 | log_information("Successfully added the cost alert " + saved_filter_name + " to the CloudCheckr account with id " + str(cc_account_id)) 70 | log_information(r7.json()) 71 | log_information("") 72 | else: 73 | log_information("Unable to add saved filter") 74 | log_information(r7.json()) 75 | 76 | 77 | def cycle_accounts(admin_api_key, env, accounts_list, saved_filter_name, emails, group_by, cost_type, include_usage_quantity, include_zero_costs): 78 | log_information("Started adding saved filters") 79 | 80 | for i in np.arange(0, np.shape(accounts_list)[0]): 81 | if check_aws(admin_api_key, env, accounts_list[i]): # this API all will work for Azure, but the parameters are different 82 | add_saved_filter(admin_api_key, env, accounts_list[i], saved_filter_name, emails, group_by, cost_type, include_usage_quantity, include_zero_costs) 83 | 84 | log_information("Finished adding saved filters") 85 | 86 | def check_invalid_env(env): 87 | """ 88 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 89 | If you are using a standalone environment, then you MUST add that to this function 90 | """ 91 | 92 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 93 | 94 | 95 | if not(env in Enviroments): 96 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 97 | return True 98 | return False 99 | 100 | 101 | def main(): 102 | try: 103 | admin_api_key = str(sys.argv[1]) 104 | except IndexError: 105 | print("Must admin_api_key") 106 | return 107 | 108 | env = "https://api.cloudcheckr.com" 109 | 110 | saved_filter_name = "Saved Filter API" 111 | 112 | # add emails here, can add multiple by separating by comma in the list 113 | emails = ["alec.rajeev+savedfilterApi3@cloudcheckr.com"] 114 | 115 | # add group_by here 116 | group_by = ["Account", "Service", "Region"] 117 | 118 | # add cost type here 119 | cost_type = "List" 120 | 121 | # add include usage quantity here 122 | include_usage_quantity = True 123 | 124 | # add include zero costs here 125 | include_zero_costs = True 126 | 127 | 128 | accounts_list = get_accounts(admin_api_key, env) 129 | 130 | if accounts_list is None: 131 | return 132 | 133 | cycle_accounts(admin_api_key, env, accounts_list, saved_filter_name, emails, group_by, cost_type, include_usage_quantity, include_zero_costs) 134 | 135 | 136 | if __name__ == '__main__': 137 | main() 138 | -------------------------------------------------------------------------------- /Onboarding/AddUsers/add_users.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import pandas as pd 4 | import numpy as np 5 | import sys 6 | import logging 7 | from pathlib import Path 8 | logging.basicConfig(filename='logging_for_adding_users.log',level=logging.INFO) 9 | 10 | """ 11 | This python script is used to add users based on the add_users_input.csv file. 12 | python3 add_users.py 0000000000000000000000000000000000000000000000000000000000000000 13 | """ 14 | 15 | def log_information(log_string): 16 | logging.info(log_string) 17 | print(log_string) 18 | 19 | 20 | def write_users_created(users_output, users_recorder): 21 | np.savetxt(users_output, users_recorder, fmt="%s", delimiter=",", newline="\n") 22 | 23 | 24 | def get_users_permissions_template_input(file_name): 25 | 26 | add_users_template_input = pd.read_csv(file_name) 27 | 28 | return add_users_template_input 29 | 30 | 31 | def get_users(env, admin_api_key): 32 | 33 | if check_invalid_env(env): 34 | return 35 | 36 | api_url = env + "/api/account.json/get_users" 37 | 38 | r7 = requests.get(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}) 39 | 40 | users_list = [] 41 | 42 | if "users_and_accounts" in r7.json(): 43 | users_and_accounts = r7.json()["users_and_accounts"] 44 | for i in np.arange(0, len(users_and_accounts)): 45 | users_list.append(users_and_accounts[i]["username"]) 46 | 47 | return users_list 48 | else: 49 | return users_list 50 | 51 | 52 | def add_user(admin_api_key, add_user_input_row): 53 | env = add_user_input_row[0] 54 | 55 | if check_invalid_env(env): 56 | return None 57 | 58 | api_url = env + "/api/account.json/add_user" 59 | 60 | available_roles = ["Administrator", "User", "BasicPlusUser", "BasicUser", "ReadonlyUser"] 61 | 62 | if not(add_user_input_row[2] in available_roles): 63 | log_information("The user " + add_user_input_row[1] + " was not added because the role " + add_user_input_row[2] + " does not exist.") 64 | return None 65 | 66 | add_user_info = json.dumps({"email": add_user_input_row[1], "user_role": add_user_input_row[2]}) 67 | 68 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = add_user_info) 69 | 70 | if "CreationStatuses" in r7.json(): 71 | log_information("Added the user " + add_user_input_row[1] + " with the role " + add_user_input_row[2]) 72 | log_information(r7.json()) 73 | return add_user_input_row[1] 74 | else: 75 | log_information("Failed to add the user " + add_user_input_row[1]) 76 | log_information(r7.json()) 77 | return None 78 | 79 | 80 | def cycle_add_users(admin_api_key, add_users_template_input, users_list): 81 | 82 | users_recorder = np.zeros((np.shape(add_users_template_input)[0]+1), dtype="U200") 83 | users_recorder[0] = "Users" 84 | log_information("Started adding users") 85 | 86 | for i in np.arange(0, np.shape(add_users_template_input)[0]): 87 | if not(add_users_template_input.iloc[i][1] in users_list): 88 | new_user = add_user(admin_api_key, add_users_template_input.iloc[i]) 89 | if not(new_user is None): 90 | users_recorder[i + 1] = new_user 91 | users_list.append(new_user) 92 | else: 93 | log_information("The user " + str(add_users_template_input.iloc[i][1]) + " was not added successfully") 94 | else: 95 | log_information("The user " + add_users_template_input.iloc[i][1] + " already exists in this account, so it was not added") 96 | log_information("") 97 | 98 | log_information("Finished adding users") 99 | return users_recorder 100 | 101 | def check_invalid_env(env): 102 | """ 103 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 104 | If you are using a standalone environment, then you MUST add that to this function 105 | """ 106 | 107 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 108 | 109 | 110 | if not(env in Enviroments): 111 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 112 | return True 113 | return False 114 | 115 | 116 | def main(): 117 | file_name = "add_users_input.csv" 118 | 119 | check_add_users_input_file = Path(file_name) 120 | 121 | if check_add_users_input_file.is_file(): 122 | add_users_template_input = get_users_permissions_template_input(file_name) 123 | else: 124 | log_information("No add_users_input.csv found. Please write file for input") 125 | return 126 | 127 | try: 128 | admin_api_key = sys.argv[1] 129 | except IndexError: 130 | print("Need admin_api_key in input") 131 | return 132 | 133 | # log_information(add_users_template_input) 134 | 135 | users_list = get_users(add_users_template_input.iloc[0][0], admin_api_key) 136 | 137 | if users_list is None: 138 | return 139 | 140 | users_recorder = cycle_add_users(admin_api_key, add_users_template_input, users_list) 141 | 142 | write_users_created("UsersCreated.csv", users_recorder) 143 | 144 | 145 | if __name__ == '__main__': 146 | main() 147 | -------------------------------------------------------------------------------- /Onboarding/UserMigration/README.md: -------------------------------------------------------------------------------- 1 | # User and Group Migration 2 | 3 | The purpose of this script is to help CloudCheckr customer's migrate their 4 | user and groups from one region to another. (such as app to eu in order to comply 5 | with GDPR) 6 | 7 | CloudCheckr's DevOps team will handle the bulk of the migration and do the heavy lifting by 8 | snapshoting the customer's RDS instance, then using the AWS Database Migration Service 9 | to migrate the rds instance to the new region. This will migrate the customer's 10 | data to the new region. 11 | 12 | This script is to help fill in some of the gaps with the migration. While the 13 | DO migration will migate all of the AWS Accounts, the users and groups and their 14 | corresponding permissions will not be migrated due to the nature of how 15 | users are stored. This script will copy the users and groups from the old region and create new users in the new region 16 | with the copied permissions. It leverages CloudCheckr's Admin API to do this. 17 | 18 | ## Getting Started 19 | 20 | To run the script you will have to have two separate CloudCheckr customers set up. 21 | The first is the original customer with all the user, groups, and accounts in 22 | the customer. 23 | 24 | The second is the customer that the users will be copied to. This customer must 25 | have only a single user that is an Admin. This Admin user must not be 26 | in the original customer and is just there as a placeholder. This customer 27 | must also have all of the same AWS Accounts and MAVs as in the original 28 | with the *same* name. This is so the use_accout parameter can 29 | be used to match them. 30 | 31 | Normally DevOps will handle the migration to meet these requirements, but 32 | you can do it as well for testing purposes. You can just add and credential 33 | the same accounts, then make sure all the mavs and accounts have the right name. 34 | When DevOps completes the migration, the Groups will be migrated but not have 35 | any permissions attached to them. You will have to delete out the groups 36 | by for example running reset_group.py. This is because there can be no 37 | duplicate group names. 38 | 39 | If you are migrating from one environment to the same environment (such as qa to qa), 40 | this can be handled by creating users with the format alec@cloudcheckr.com to alec+migration@cloudcheckr.com. One limitation of this is that no emails can have 41 | the "+trick@cloudcheckr.com" in them. Instead, they must have the standard format. 42 | 43 | ### Customer Communication 44 | 45 | PartnerSysAdmin users will NOT be migrated with this script because 46 | the Admin API can not be used to create PartnerSysAdmins. This is on-purpose 47 | because each PartnerSysAdmin should be carefully created and activated 48 | due to their heightened security permissions within CloudCheckr. 49 | 50 | ### Prerequisites 51 | 52 | What things you need to install the software and how to install them 53 | 54 | ``` 55 | python 3 56 | pip 57 | requests 58 | numpy 59 | ``` 60 | 61 | ### Installing 62 | 63 | A step by step series of examples that tell you have to get a development env running. 64 | Download migrate_users_and_groups.py, Group.py, and reset_group.py 65 | Then install the required packages. 66 | 67 | ``` 68 | pip install requests 69 | ``` 70 | 71 | And then 72 | 73 | ``` 74 | pip install numpy 75 | ``` 76 | 77 | 78 | ## Running the script 79 | 80 | To run this python code you need the original environment such as api. 81 | Then the original Admin API Key. 82 | Then the new environment such as eu. 83 | Then the new Admin API Key. 84 | 85 | The available regions currently are api, au, eu, gov, and qa. 86 | Currently app is not available because api calls should not 87 | be run against app. 88 | 89 | 90 | For Example (invalid api keys in example) 91 | 92 | 93 | ``` 94 | python migrate_users_and_groups.py 95 | 96 | python migrate_users_and_groups.py eu au 97 | ``` 98 | 99 | If you need to reset the users and groups in the new region for testing purposes, 100 | you can run reset_users_and_groups.py. This will delete all the users and groups 101 | in the new region and then create the placeholder admin user. 102 | 103 | ``` 104 | python reset_users_and_groups.py qa 105 | ``` 106 | 107 | ### What Each file does. 108 | 109 | migrate_users_and_groups.py ----------- is the main file that is used to migrate users and groups 110 | 111 | Group.py ------------------------------ is a python class file used to create the group object that is used to help keep track of users in groups 112 | 113 | reset_users_and_groups.py ------------- is used to reset users and groups in the new region if something goes wrong. Can be used for testing purposes as well. 114 | 115 | ## Deployment 116 | 117 | It is recommended to run this on a unix based system with enough compute power 118 | to run large and numerous api calls. Each post api call made will be logged 119 | for tracking purposes. 120 | 121 | screen -r session3 can be used to run a screen while doing other things 122 | on the console. 123 | 124 | ## Built With 125 | 126 | * python 127 | * numpy 128 | * requests 129 | 130 | ## Author(s) 131 | 132 | * **Alec Rajeev** - *CloudCheckr Support - Tier 2* 133 | * **Brett Gadberry** - *Senior Technical Account Manager* 134 | 135 | 136 | ## License 137 | 138 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details 139 | -------------------------------------------------------------------------------- /Cost/FindUnmappedAccounts/FindUnmappedAccounts.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Find Unmapped Accounts in CloudCheckr function", 4 | "Parameters": { 5 | "CronExpression": { 6 | "Type": "String", 7 | "Description": "Cron expression for triggering the function", 8 | "Default": "cron(0 13-23 ? * MON-FRI *)" 9 | }, 10 | "SourceEmailAddress": { 11 | "Type": "String", 12 | "Description": "Email address for sending notifications" 13 | }, 14 | "DestEmailAddress": { 15 | "Type": "String", 16 | "Description": "Email address for receiving notifications" 17 | }, 18 | "KMSKey": { 19 | "Type": "String", 20 | "Description": "Arn of the KMS key used to encrypt the cc_admin_access_key secure string" 21 | }, 22 | "S3Bucket": { 23 | "Type": "String", 24 | "Description": "Name of the bucket where the zip file is" 25 | }, 26 | "S3Key": { 27 | "Type": "String", 28 | "Description": "Path to the zip file within the bucket" 29 | } 30 | }, 31 | "Metadata": { 32 | "AWS::CloudFormation::Interface": { 33 | "ParameterGroups": [ 34 | { 35 | "Label": { 36 | "default": "Deployment Parameters" 37 | }, 38 | "Parameters": [ 39 | "S3Bucket", 40 | "S3Key" 41 | ] 42 | }, 43 | { 44 | "Label": { 45 | "default": "Notification Parameters" 46 | }, 47 | "Parameters": [ 48 | "SourceEmailAddress", 49 | "DestEmailAddress" 50 | ] 51 | }, 52 | ] 53 | } 54 | }, 55 | "Resources": { 56 | "CWCronJob": { 57 | "Type": "AWS::Events::Rule", 58 | "Properties": { 59 | "Description": "Triggers the find-unmapped-accounts function", 60 | "Name": "Find-Unmapped-Accounts-Cron-Job", 61 | "ScheduleExpression": { 62 | "Ref": "CronExpression" 63 | }, 64 | "State": "ENABLED", 65 | "Targets": [ 66 | { 67 | "Arn": { 68 | "Fn::GetAtt": [ 69 | "FindUnmappedAccountsFunction", 70 | "Arn" 71 | ] 72 | }, 73 | "Id": "FindUnmappedAccounts", 74 | "Input": { 75 | "Fn::Join": [ 76 | "", 77 | [ 78 | "{", 79 | "\"notificationsBool\": \"true\"", 80 | "}" 81 | ] 82 | ] 83 | } 84 | } 85 | ] 86 | } 87 | }, 88 | "FindUnmappedAccountsRole": { 89 | "Type": "AWS::IAM::Role", 90 | "Properties": { 91 | "AssumeRolePolicyDocument": { 92 | "Version": "2012-10-17", 93 | "Statement": [ 94 | { 95 | "Effect": "Allow", 96 | "Principal": { 97 | "Service": [ 98 | "lambda.amazonaws.com" 99 | ] 100 | }, 101 | "Action": [ 102 | "sts:AssumeRole" 103 | ] 104 | } 105 | ] 106 | }, 107 | "RoleName": "lambda_find_unmapped_accounts", 108 | "Path": "/", 109 | "Policies": [ 110 | { 111 | "PolicyName": "lambda-find-unmapped-accounts-policy", 112 | "PolicyDocument": { 113 | "Version": "2012-10-17", 114 | "Statement": [ 115 | { 116 | "Effect": "Allow", 117 | "Action": [ 118 | "logs:CreateLogGroup", 119 | "logs:CreateLogStream", 120 | "logs:PutLogEvents" 121 | ], 122 | "Resource": "arn:aws:logs:*:*:*" 123 | }, 124 | { 125 | "Effect": "Allow", 126 | "Action": [ 127 | "ses:SendEmail" 128 | ], 129 | "Resource": "*" 130 | }, 131 | { 132 | "Sid": "KMSDecrypt", 133 | "Effect": "Allow", 134 | "Action": [ 135 | "kms:Decrypt" 136 | ], 137 | "Resource": { "Ref": "KMSKey" } 138 | }, 139 | { 140 | "Sid": "ParameterStore", 141 | "Effect": "Allow", 142 | "Action": "ssm:GetParameters", 143 | "Resource": "*" 144 | } 145 | ] 146 | } 147 | } 148 | ] 149 | } 150 | }, 151 | "FindUnmappedAccountsFunction": { 152 | "Type": "AWS::Lambda::Function", 153 | "Properties": { 154 | "FunctionName": "find_unmapped_accounts", 155 | "Description" : "Detects payee accounts not part of a CloudCheckr account family and alerts via SES", 156 | "Handler": "find_unmapped_accounts.handler", 157 | "Runtime": "nodejs4.3", 158 | "Timeout": 60, 159 | "Role": { 160 | "Fn::GetAtt": [ 161 | "FindUnmappedAccountsRole", 162 | "Arn" 163 | ] 164 | }, 165 | "Environment": { 166 | "Variables": { 167 | "sourceAddr": { "Ref": "SourceEmailAddress" }, 168 | "destAddr": { "Ref": "DestEmailAddress" } 169 | } 170 | }, 171 | "Code": { 172 | "S3Bucket": { 173 | "Ref": "S3Bucket" 174 | }, 175 | "S3Key": { 176 | "Ref": "S3Key" 177 | } 178 | } 179 | } 180 | } 181 | }, 182 | "Outputs": {} 183 | } 184 | -------------------------------------------------------------------------------- /Onboarding/CreateGroups/create_groups.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import pandas as pd 4 | import numpy as np 5 | import sys 6 | import logging 7 | from pathlib import Path 8 | logging.basicConfig(filename='logging_for_creating_groups.log',level=logging.INFO) 9 | 10 | """ 11 | This python script is used to create groups based on the create_groups_input.csv file. 12 | python3 create_groups.py 0000000000000000000000000000000000000000000000000000000000000000 13 | """ 14 | 15 | def log_information(log_string): 16 | logging.info(log_string) 17 | print(log_string) 18 | 19 | 20 | def get_group_names_template_input(file_name): 21 | 22 | group_names_template_input = pd.read_csv(file_name) 23 | 24 | return group_names_template_input 25 | 26 | 27 | def write_groups_created(groups_output, group_recorder): 28 | np.savetxt(groups_output, group_recorder, fmt="%s", delimiter=",", newline="\n") 29 | 30 | def create_group(admin_api_key, env, group_name): 31 | 32 | 33 | if check_invalid_env(env): 34 | return None 35 | 36 | api_url = env + "/api/account.json/create_group" 37 | 38 | group_info = json.dumps({"name": group_name}) 39 | 40 | r7 = requests.post(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}, data = group_info) 41 | 42 | group_id = None 43 | 44 | if "group_id" in r7.json(): 45 | group_id = r7.json()["group_id"] 46 | log_information("Created the Group: " + group_name + " with id: " + str(group_id)) 47 | log_information(r7.json()) 48 | else: 49 | log_information("Failed to create the group: " + str(group_name)) 50 | log_information(r7.json()) 51 | 52 | return group_id 53 | 54 | def get_groups(env, admin_api_key): 55 | """ 56 | You have to check for and handle duplicate groups because historically CloudCheckr used to allow for duplicate group creation. 57 | """ 58 | 59 | if check_invalid_env(env): 60 | return None, None 61 | 62 | api_url = env + "/api/account.json/get_groups" 63 | 64 | r7 = requests.get(api_url, headers = {"Content-Type": "application/json", "access_key": admin_api_key}) 65 | 66 | groups_list = [] 67 | groups_duplicate_list = [] 68 | 69 | if "GroupNames" in r7.json(): 70 | GroupNames = r7.json()["GroupNames"] 71 | for i in np.arange(0, len(GroupNames)): 72 | groups_list.append(GroupNames[i]) 73 | for i in np.arange(0, len(GroupNames)): 74 | if groups_list.count(GroupNames[i]) > 1: 75 | groups_duplicate_list.append(GroupNames[i]) 76 | log_information("Found duplicate group: " + GroupNames[i] + ". We recommend renaming it through the UI to remove duplicates.") 77 | 78 | return groups_list, groups_duplicate_list 79 | else: 80 | return groups_list, groups_duplicate_list 81 | 82 | def cycle_create_groups(admin_api_key, group_names_template_input, groups_list): 83 | 84 | group_recorder = np.zeros((np.shape(group_names_template_input)[0] + 1, 2), dtype="U200") 85 | group_recorder[0][0] = "GroupName" 86 | group_recorder[0][1] = "group_id" 87 | 88 | for i in np.arange(0, np.shape(group_names_template_input)[0]): 89 | if not(group_names_template_input.iloc[i][1] in groups_list): 90 | group_id = create_group(admin_api_key, group_names_template_input.iloc[i][0], group_names_template_input.iloc[i][1]) 91 | if group_id is None: 92 | group_id = "Failed" 93 | else: 94 | groups_list.append(group_names_template_input.iloc[i][1]) 95 | group_recorder[i + 1][0] = str(group_names_template_input.iloc[i][1]) 96 | group_recorder[i + 1][1] = str(group_id) 97 | else: 98 | log_information("A group with the name " + group_names_template_input.iloc[i][1] + " has already been created. Please rename it") 99 | 100 | write_groups_created("GroupsCreated.csv", group_recorder) 101 | 102 | 103 | def check_invalid_env(env): 104 | """ 105 | This will check for an invalid enviroment. Currently it will only check for api, eu, au, or gov. 106 | If you are using a standalone environment, then you MUST add that to this function 107 | """ 108 | 109 | Enviroments = ["https://api.cloudcheckr.com", "https://eu.cloudcheckr.com", "https://au.cloudcheckr.com", "https://gov.cloudcheckr.com", "https://qa.cloudcheckr.com"] 110 | 111 | 112 | if not(env in Enviroments): 113 | log_information("The environment " + str(env) + " is not valid. If this is a standalone environment, please add the url to the check_invalid_env function.") 114 | return True 115 | return False 116 | 117 | 118 | def main(): 119 | file_name = "create_groups_input.csv" 120 | 121 | check_groups_input_template = Path(file_name) 122 | 123 | if check_groups_input_template.is_file(): 124 | group_names_template_input = get_group_names_template_input(file_name) 125 | else: 126 | log_information("No group_permissions_input.csv found. Please write file for input") 127 | return 128 | 129 | try: 130 | admin_api_key = sys.argv[1] 131 | except IndexError: 132 | print("Need admin_api_key in input") 133 | return 134 | 135 | groups_list, groups_duplicate_list = get_groups(group_names_template_input.iloc[0][0], admin_api_key) 136 | 137 | if groups_list is None: 138 | return 139 | 140 | if len(groups_duplicate_list) > 0: 141 | log_information("Please remove duplicate group names before proceeding.") 142 | return 143 | else: 144 | log_information("No duplicate groups found, please proceed.") 145 | 146 | # print(groups_list) 147 | 148 | cycle_create_groups(admin_api_key, group_names_template_input, groups_list) 149 | 150 | 151 | if __name__ == '__main__': 152 | main() -------------------------------------------------------------------------------- /Onboarding/GetGroupAcls/AzurePermissions.csv: -------------------------------------------------------------------------------- 1 | Acls,Section,Permission 2 | 536f7e9a-c15f-4952-a289-e870f3a09930[CC_Delimiter]07ac5ec8-c453-494a-b7ed-469e3090b2b5,Generic,See List Costs 3 | 02bcaa5a-7953-4932-88d5-0d54fdf01c51[CC_Delimiter]f3dc0618-c139-4f28-99d5-0f55ac6dead9,Savings,Cost Savings 4 | 5b840bb5-b887-49e6-a8aa-8b7a214946fe[CC_Delimiter]147a029d-7f8c-4467-b7ce-53aac7a7ea9e,BestPractices,Best Practices 5 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]c6512f4f-5ab6-410b-bfee-e91b4cfacdcb,Inventory,Custom Reports 6 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]023cc73b-2c8a-49c6-bfaa-ea3010bea825,Inventory,Inventory Summary 7 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]96bd8797-0019-4703-b7cd-1ae3c6956c31,Inventory,Virtual Machine Summary 8 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]435af095-10c2-4ecf-978d-534f7a7c6940,Inventory,List of Virtual Machines 9 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]d6d97225-b47e-44d9-bb62-aba975edfe04,Inventory,Storage Account Summary 10 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]1bd64805-a1f1-40f0-9d53-620954aa03dc,Inventory,List of Blob Containers 11 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]2ec4c13c-3d18-4aaf-b369-d2d169aef78b,Inventory,List of Storage Queues 12 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]36c99dad-2580-481a-9af5-a4be7a12f43c,Inventory,List of Storage Accounts 13 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]307002fe-f593-46f8-b0a5-c0c148d99e68,Inventory,SQL Server Summary 14 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]2bb7457c-4f57-4aa9-bf3c-ae9e78747770,Inventory,List of SQL Servers 15 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]8e8df32a-7110-43fc-9081-15cab420075f,Inventory,Redis Cache Summary 16 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]138c67b3-2256-485b-963a-e62193c2a174,Inventory,List of Redis Caches 17 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]926d9d57-8597-4788-83f7-2207a85bdc52,Inventory,Resource Group Summary 18 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]72b63637-9d14-4bd5-b020-3a9ea81ef4d0,Inventory,List of Resource Groups 19 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]92c23d35-f41c-40c7-856c-921d6f8cd855,Inventory,App Service Plan Summary 20 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]0902e4e6-895b-4d62-81ef-452ba3f56704,Inventory,List of App Service Plans 21 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]0a347d44-eb5d-4ffb-99c8-591e719d3148,Inventory,Traffic Manager Profile Summary 22 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]a2cb502c-9875-4510-bed6-9c92258d2212,Inventory,List of Traffic Manager Profiles 23 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]8fc713e7-798c-4dfd-b94f-bf64fe3e474e,Inventory,List of HDInsight Clusters 24 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]5f2361e8-51eb-4585-ab7c-f4b39094cf92,Inventory,HDInsight Cluster Summary 25 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]e631dd3c-f0c1-49bb-bb8f-055ace43353e,Inventory,Virtual Machine History by Time 26 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]ec2626b2-fc0d-4863-a069-059dfc13dfe8,Inventory,History by Virtual Machine 27 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]a34850bb-9c2b-473f-8d95-fca260e6fe23,Inventory,List of Scale Sets 28 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]03e9cf21-5701-4bb1-b47b-ed6f75dcf21b,Inventory,Virtual Machine Scale Set Summary 29 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]aa726f13-c06f-4e10-89aa-2b866b6ddd3e,Inventory,List of Images 30 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]b10b3180-5e5c-45b1-aae3-ceb0c2d8a64d,Inventory,Image Summary 31 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]19b297e3-fc64-4ffd-8009-60af848727c9,Inventory,List of ManagedDisks 32 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]bee542ee-9c20-4d70-a04d-3e2399a04109,Inventory,Managed Disk Summary 33 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]e4db88b1-f35c-49c7-a531-4dda767ad4d0,Inventory,Snapshot Summary 34 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]89d569d8-d40b-4016-bae8-f1763900362a,Inventory,List of Snapshots 35 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]9693ff4a-f88a-4939-b7e1-c1ccd753be47,Inventory,Service Request Summary 36 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]d8d5c451-2c1a-4d23-9c49-ee8606368ce3,Inventory,List of Service Requests 37 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]274cdeef-5523-494d-a3c5-60dea6b85990,Inventory,Service Bus Summary 38 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]30f8479f-d9da-4f7c-aca1-d8bdfbc7e6bd,Inventory,List of Service Buses 39 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]230caf71-2355-4795-91ce-ea7a0f4c69d5,Inventory,Untagged 40 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]a6ca8f5c-5941-4651-98b1-e0c0fa8dc473,Inventory,Container Service Summary 41 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]cdcd83df-40ec-4f6f-bbee-79a0a27ae5d7,Inventory,List of Container Services 42 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]dc863e01-9c64-4834-a514-7b9c1d7693c6,Inventory,Users Summary 43 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]f0679ff6-3793-459b-813a-9788a90dad33,Inventory,List of Users 44 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]85b615cf-267b-4962-8943-4fa89ab6e407,Inventory,Licenses Summary 45 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]091c169f-0ffd-4a40-8c74-f1b8942dd1d9,Inventory,List of Licenses 46 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]000a75ec-526e-4364-ada2-79e6a67fcf8b,Inventory,Activity by User 47 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]4f77df06-7682-488d-9101-dd8870694251,Inventory,Activity by User 48 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]03fc756e-7e19-44ea-A6c3-8645298ccb28,Inventory,Overall Usage 49 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]a0c2e399-9846-4e26-8522-0f41914f0422,Inventory,Activity by User 50 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]e0dc4ee7-7ff0-4277-8d18-274c1903800a,Inventory,Device Usage by User 51 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]d69ff23f-8d32-4b31-ba8e-ed4a391f85d6,Inventory,Activity by User 52 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]1bc0bf1c-a734-4b4c-b40d-558a244619c8,Inventory,Activity by User 53 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]e98493e3-f295-49ff-a7f1-a655b2c986b0,Inventory,Usage by User 54 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]833c2a9e-3031-4237-a634-97e25a88aa13,Inventory,Activity by User 55 | dd82ecd7-c590-490f-9b3a-f22990a1b500[CC_Delimiter]5b67be00-a50b-43a9-8049-c8f6e6a0ad00,Inventory,Overall Usage 56 | -------------------------------------------------------------------------------- /Onboarding/CredentialAWSAccounts/CredentialAWSAccounts.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | import requests 4 | import configparser 5 | 6 | 7 | global bearerToken 8 | global customerNumber 9 | global roleIdentifier 10 | """ 11 | this script is designed to be used with a stack set. 12 | if we configure the stack set to create predictible arns we can quickly and easily credential the accounts using this script. 13 | "roleArn": "arn:aws:iam::"+subscriptionId+":role/cc-iam-role" 14 | Do this by adding ("RoleName" : cc-iam-role) to the cloudformation template. This removes the random string of characters appended normally at the end. 15 | """ 16 | def main(): 17 | 18 | config = configparser.RawConfigParser() 19 | config.read('config.txt') 20 | 21 | APIKey = config.get('config', 'APIKey') 22 | APISecret = config.get('config', 'APISecret') 23 | customerNumber = config.get('config', 'customerNumber') 24 | roleIdentifier = config.get('config', 'roleIdentifier') 25 | 26 | 27 | print("getting token") 28 | bearerToken = get_access_token("https://auth-us.cloudcheckr.com/auth/connect/token", APIKey, APISecret) 29 | 30 | getAWSAccounts(customerNumber, bearerToken, roleIdentifier) 31 | 32 | return 33 | 34 | 35 | 36 | 37 | """ 38 | CloudCheckr API call for PutAWSCredentials 39 | requirements: 40 | predictable ARNs 41 | "roleArn": "arn:aws:iam::"+subscriptionId+":role/cc-iam-role" 42 | Do this by adding "RoleName" : cc-iam-role to the cloudformation template. This removes the random string of characters appended normally at the end. 43 | """ 44 | 45 | def setAWSCred(customer_number, bearer_token, account_number, providerId, roleIdentifier): 46 | print("running setAWSCred") 47 | #print("Customer_Number: ", customer_number) 48 | url = "https://api-us.cloudcheckr.com/credential/v1/customers/"+str(customer_number)+"/accounts/"+account_number+"/credentials/aws" 49 | #print("url: ", url) 50 | payload = json.dumps({ 51 | "item": { 52 | "regionGroup": "Commercial", 53 | 54 | "crossAccountRole": { 55 | "roleArn": "arn:aws:iam::"+providerId+":role/"+roleIdentifier 56 | }, 57 | } 58 | }) 59 | #print("Payload", payload) 60 | headers = { 61 | 'Accept': 'text/plain', 62 | 'Authorization': 'Bearer ' + bearer_token 63 | } 64 | response = requests.request("PUT", url, headers=headers, data=payload) 65 | 66 | print("response: ", response.text) 67 | 68 | 69 | def getAWSAccounts(customer_number, bearer_token, role_id): 70 | results = [] 71 | print("getting all accounts") 72 | 73 | url = "https://api-us.cloudcheckr.com/customer/v1/customers/"+str(customer_number)+"/accounts?accountTypes=General" 74 | payload = None 75 | headers = { 76 | 'Accept': 'text/plain', 77 | 'Authorization': 'Bearer ' + bearer_token 78 | } 79 | response = requests.request("GET", url, headers=headers, data=payload) 80 | 81 | 82 | account_json = json.loads(response.text) 83 | results = account_json['items'] 84 | print("results: ",results) 85 | #print("account_json: ", account_json) 86 | #print("next key:") 87 | nextKey = None 88 | if 'pagination' in account_json: 89 | print("pagination key is: ", account_json['pagination']['nextKey']) 90 | nextKey = account_json['pagination']['nextKey'] 91 | 92 | while nextKey is not None: 93 | print("running while loop, nextKey detected") 94 | url = "https://api-us.cloudcheckr.com/customer/v1/customers/"+str(customer_number)+"/accounts?accountTypes=General&$paginationKey="+nextKey 95 | payload = None 96 | headers = { 97 | 'Accept': 'text/plain', 98 | 'Authorization': 'Bearer ' + bearer_token 99 | } 100 | response_next = requests.request("GET", url, headers=headers, data=payload) 101 | response_json = json.loads(response_next.text) 102 | #print("response_json: ", response_json) 103 | if 'nextKey' in response_json['pagination']: 104 | nextKey = response_json['pagination']['nextKey'] 105 | print("nextKey: ", nextKey) 106 | else: 107 | nextKey = None 108 | results.extend(response_json['items']) 109 | 110 | 111 | #loop through non credentailed accounts and call the credential after gathering external ID. 112 | for items in results: 113 | 114 | #print("item: ", items) 115 | #print("provider: ", items["provider"]) 116 | if items["provider"] == "AWS" and items['credentialVerificationStatus'] == 'NotConfigured' or items["provider"] == "AWS" and items['credentialVerificationStatus'] == 'Failed' or items["provider"] == "AWS" and items['credentialVerificationStatus'] == 'Empty' : 117 | print("this item is not credentialed: ", items) 118 | account_number = items['id'] 119 | external = get_external_id(customer_number, account_number, bearer_token) 120 | #print("external returned: ", external) 121 | if 'providerIdentifier' in items: 122 | provider_id = items['providerIdentifier'] 123 | setAWSCred(customer_number, bearer_token, account_number, provider_id, role_id) 124 | 125 | 126 | 127 | 128 | 129 | def get_external_id(customerID, accountID, bearerToken): 130 | region = "Commercial" 131 | url = "https://api-us.cloudcheckr.com/credential/v1/customers/"+str(customerID)+"/accounts/"+str(accountID)+"/external-id/aws/"+region 132 | payload = None 133 | headers = { 134 | 'Accept': 'text/plain', 135 | 'Authorization': 'Bearer ' + bearerToken 136 | } 137 | credentials_response = requests.request("GET", url, headers=headers, data=payload) 138 | response_json = json.loads(credentials_response.text) 139 | 140 | #print("externalID json: ", response_json) 141 | return response_json 142 | 143 | #Creates the bearer token 144 | def get_access_token(url, client_id, client_secret): 145 | response = requests.post( 146 | url, 147 | data={"grant_type": "client_credentials"}, 148 | auth=(client_id, client_secret), 149 | ) 150 | #print("response", response) 151 | return response.json()["access_token"] 152 | 153 | 154 | main() 155 | 156 | -------------------------------------------------------------------------------- /Onboarding/CreateGroups/logging_for_creating_groups.log: -------------------------------------------------------------------------------- 1 | INFO:root:Created the Group GroupAlpha with id: 0f0f4732-29b0-49e4-a99f-b81cce9cda96 2 | INFO:root:{'group_id': '0f0f4732-29b0-49e4-a99f-b81cce9cda96', 'Code': 200, 'Message': 'OK'} 3 | INFO:root:Created the Group GroupBeta with id: 5bfcfd1c-c555-461e-9e26-83e3aec78624 4 | INFO:root:{'group_id': '5bfcfd1c-c555-461e-9e26-83e3aec78624', 'Code': 200, 'Message': 'OK'} 5 | INFO:root:Created the Group GroupAlpha with id: bad3eec8-aaf3-4217-b216-35fc1ead9e22 6 | INFO:root:{'group_id': 'bad3eec8-aaf3-4217-b216-35fc1ead9e22', 'Code': 200, 'Message': 'OK'} 7 | INFO:root:Created the Group GroupBeta with id: c81a5e08-e0c3-4889-9410-536971f09881 8 | INFO:root:{'group_id': 'c81a5e08-e0c3-4889-9410-536971f09881', 'Code': 200, 'Message': 'OK'} 9 | INFO:root:Created the Group GroupAlpha with id: 6fdfe262-d6ac-4bf7-a576-e4d7dfb9d670 10 | INFO:root:{'group_id': '6fdfe262-d6ac-4bf7-a576-e4d7dfb9d670', 'Code': 200, 'Message': 'OK'} 11 | INFO:root:Created the Group GroupBeta with id: 30517b30-7bf7-40cb-a248-083b4cd26ed8 12 | INFO:root:{'group_id': '30517b30-7bf7-40cb-a248-083b4cd26ed8', 'Code': 200, 'Message': 'OK'} 13 | INFO:root:Created the Group GroupAlpha with id: 8dda8065-82b0-4615-88ee-5d1f6c52eb22 14 | INFO:root:{'group_id': '8dda8065-82b0-4615-88ee-5d1f6c52eb22', 'Code': 200, 'Message': 'OK'} 15 | INFO:root:Created the Group GroupBeta with id: 3fc9d156-9333-4e65-8adc-f0226374c62e 16 | INFO:root:{'group_id': '3fc9d156-9333-4e65-8adc-f0226374c62e', 'Code': 200, 'Message': 'OK'} 17 | INFO:root:Created the Group GroupAlpha with id: 70995bf9-fe9c-4e0e-a07f-2f6b694c3fd5 18 | INFO:root:{'group_id': '70995bf9-fe9c-4e0e-a07f-2f6b694c3fd5', 'Code': 200, 'Message': 'OK'} 19 | INFO:root:Created the Group GroupBeta with id: 7484fe22-76cb-45f1-8443-6d551f8ee6a6 20 | INFO:root:{'group_id': '7484fe22-76cb-45f1-8443-6d551f8ee6a6', 'Code': 200, 'Message': 'OK'} 21 | INFO:root:Created the Group: GroupAlpha with id: 3ddc2491-b4ea-4e06-9813-6528dc298cae 22 | INFO:root:{'group_id': '3ddc2491-b4ea-4e06-9813-6528dc298cae', 'Code': 200, 'Message': 'OK'} 23 | INFO:root:Created the Group: GroupBeta with id: d04a364b-2c0a-4aa0-b631-64346ccb6ce8 24 | INFO:root:{'group_id': 'd04a364b-2c0a-4aa0-b631-64346ccb6ce8', 'Code': 200, 'Message': 'OK'} 25 | INFO:root:Created the Group: GroupAlpha with id: 3295eddf-4ebd-4310-a90d-abc8cde83366 26 | INFO:root:{'group_id': '3295eddf-4ebd-4310-a90d-abc8cde83366', 'Code': 200, 'Message': 'OK'} 27 | INFO:root:Created the Group: GroupBeta with id: 52277c68-1420-4426-99b0-7ee008c123d5 28 | INFO:root:{'group_id': '52277c68-1420-4426-99b0-7ee008c123d5', 'Code': 200, 'Message': 'OK'} 29 | INFO:root:Created the Group: GroupZeta with id: acf2e371-cc52-484f-9da8-e8746e94858b 30 | INFO:root:{'group_id': 'acf2e371-cc52-484f-9da8-e8746e94858b', 'Code': 200, 'Message': 'OK'} 31 | INFO:root:Created the Group: GroupIota with id: 86748a14-510a-4aaf-889a-b0b3ba503adb 32 | INFO:root:{'group_id': '86748a14-510a-4aaf-889a-b0b3ba503adb', 'Code': 200, 'Message': 'OK'} 33 | INFO:root:No duplicate groups found, please proceed. 34 | INFO:root:Created the Group: GroupZeta with id: a42977d0-2fd9-40b8-accc-f6638a00e1f7 35 | INFO:root:{'group_id': 'a42977d0-2fd9-40b8-accc-f6638a00e1f7', 'Code': 200, 'Message': 'OK'} 36 | INFO:root:Created the Group: GroupIota with id: b13dab59-c7b0-49bf-9093-63df1ef02137 37 | INFO:root:{'group_id': 'b13dab59-c7b0-49bf-9093-63df1ef02137', 'Code': 200, 'Message': 'OK'} 38 | INFO:root:A group with the name GroupIota2 has already been created. Please rename it 39 | INFO:root:A group with the name GroupIota3 has already been created. Please rename it 40 | INFO:root:Found duplicate group: GroupIota. We recommend renaming it through the UI to remove duplicates. 41 | INFO:root:Found duplicate group: GroupIota. We recommend renaming it through the UI to remove duplicates. 42 | INFO:root:Found duplicate group: GroupZeta. We recommend renaming it through the UI to remove duplicates. 43 | INFO:root:Found duplicate group: GroupZeta. We recommend renaming it through the UI to remove duplicates. 44 | INFO:root:Please remove duplicate group names before proceeding. 45 | INFO:root:Found duplicate group: GroupZeta. We recommend renaming it through the UI to remove duplicates. 46 | INFO:root:Found duplicate group: GroupZeta. We recommend renaming it through the UI to remove duplicates. 47 | INFO:root:Please remove duplicate group names before proceeding. 48 | INFO:root:No duplicate groups found, please proceed. 49 | INFO:root:Created the Group: GroupZeta with id: 0d0d51cd-fbc2-429e-ba3b-b94b9e79d340 50 | INFO:root:{'group_id': '0d0d51cd-fbc2-429e-ba3b-b94b9e79d340', 'Code': 200, 'Message': 'OK'} 51 | INFO:root:Created the Group: GroupIota with id: 273c791b-2518-450e-b8e8-d09a8c020fc9 52 | INFO:root:{'group_id': '273c791b-2518-450e-b8e8-d09a8c020fc9', 'Code': 200, 'Message': 'OK'} 53 | INFO:root:A group with the name GroupIota2 has already been created. Please rename it 54 | INFO:root:A group with the name GroupIota3 has already been created. Please rename it 55 | INFO:root:No duplicate groups found, please proceed. 56 | INFO:root:A group with the name GroupZeta has already been created. Please rename it 57 | INFO:root:A group with the name GroupIota has already been created. Please rename it 58 | INFO:root:Created the Group: GroupIota2 with id: c4c6a172-bce2-41eb-8233-f9a51cb6e606 59 | INFO:root:{'group_id': 'c4c6a172-bce2-41eb-8233-f9a51cb6e606', 'Code': 200, 'Message': 'OK'} 60 | INFO:root:Created the Group: GroupIota3 with id: 567cd59d-03a9-4f17-8bee-15e1ac800fc8 61 | INFO:root:{'group_id': '567cd59d-03a9-4f17-8bee-15e1ac800fc8', 'Code': 200, 'Message': 'OK'} 62 | INFO:root:A group with the name GroupIota2 has already been created. Please rename it 63 | INFO:root:No duplicate groups found, please proceed. 64 | INFO:root:Created the Group: Group Barcelona with id: d187ba0b-f4cd-477c-a345-7d90c9139bc9 65 | INFO:root:{'group_id': 'd187ba0b-f4cd-477c-a345-7d90c9139bc9', 'Code': 200, 'Message': 'OK'} 66 | INFO:root:Created the Group: Group Roma with id: fe75fff7-8324-47ab-908e-32de9d72ae87 67 | INFO:root:{'group_id': 'fe75fff7-8324-47ab-908e-32de9d72ae87', 'Code': 200, 'Message': 'OK'} 68 | INFO:root:The environment https://api2.cloudcheckr.com is not valid. If this is a standalone environment, please add the url to the check_invalid_env function. 69 | INFO:root:Created the Group: Group Firenze with id: a0f092a5-9234-4e8f-861e-bc625dbe66bf 70 | INFO:root:{'group_id': 'a0f092a5-9234-4e8f-861e-bc625dbe66bf', 'Code': 200, 'Message': 'OK'} 71 | INFO:root:Created the Group: Group Milan with id: b0c9c0d9-c8d6-4692-bc15-aa5db4daee25 72 | INFO:root:{'group_id': 'b0c9c0d9-c8d6-4692-bc15-aa5db4daee25', 'Code': 200, 'Message': 'OK'} 73 | -------------------------------------------------------------------------------- /Cost/FindUnmappedAccounts/find_unmapped_accounts.js: -------------------------------------------------------------------------------- 1 | const request = require('sync-request'); 2 | const AWSXRay = require('aws-xray-sdk-core'); 3 | const AWS = AWSXRay.captureAWS(require('aws-sdk')); 4 | AWS.config.update({region: process.env.AWS_REGION}); 5 | var ssm = new AWS.SSM(); 6 | 7 | const api_base = "https://api2.cloudcheckr.com/"; 8 | var cc_admin_access_key = ''; 9 | 10 | function processEvent(event, context, callback) { 11 | 12 | var masterPayerArr; 13 | try { 14 | var params = { 15 | Names: [ 16 | 'html_encoded_semicolon_separated_master_payers' 17 | ] 18 | }; 19 | 20 | ssm.getParameters(params, function(err, data) { 21 | if (err) { 22 | console.log(err, err.stack); // an error occurred 23 | callback(err); 24 | } else if (data['Parameters'] == undefined) { 25 | callback("SSM was able to reach parameter store, but no parameter was found for the payer accounts."); 26 | } else { 27 | masterPayerArr = data['Parameters'][0]['Value'].split(','); 28 | 29 | var account_list; 30 | console.log(masterPayerArr); 31 | 32 | for (var masterPayerNum in masterPayerArr) { 33 | var masterPayer = masterPayerArr[masterPayerNum]; 34 | 35 | var options = { 36 | host: api_base, 37 | path: 'api/billing.json/get_account_family?access_key=' + cc_admin_access_key + '&use_account=' + masterPayer 38 | }; 39 | 40 | console.log('Getting the list of account families for ' + masterPayer + '...'); 41 | var response = request('GET', options['host'] + options['path']); 42 | var response_array; 43 | 44 | if (response.statusCode == 200) { 45 | //console.log(response.body); // Show the response 46 | response_array = JSON.parse(response.body); 47 | //console.log(response_array); 48 | if (response_array['UnmappedAccounts'].length === 0) { 49 | console.log('No unmapped accounts found in ' + masterPayer + '.'); 50 | //callback(null, false); /* Indicates success with information returned to the caller. */ 51 | } else { 52 | console.log('Unmapped accounts found in ' + masterPayer + '.'); 53 | 54 | response_array['UnmappedAccounts'].forEach(function(entry) { 55 | if (account_list == undefined) { 56 | account_list = entry; 57 | } else { 58 | account_list += '\n' + entry; 59 | } 60 | }); 61 | } 62 | } else { 63 | console.log('Error: ' + response.statusCode + ' ' + response.body + '. Exiting...'); 64 | context.fail('Could not retrieve data from CloudCheckr'); 65 | } 66 | } 67 | 68 | if (account_list != undefined && (event.notificationsBool === "true" || event.notificationsBool == undefined)) { 69 | var ses = new AWS.SES(); 70 | 71 | var params = { 72 | Destination: { 73 | BccAddresses: [], 74 | CcAddresses: [], 75 | ToAddresses: [ 76 | process.env.destAddr 77 | ] 78 | }, 79 | Message: { 80 | Body: { 81 | Html: { 82 | Charset: "UTF-8", 83 | Data: "Hello,

Some accounts were found in CloudCheckr which are not mapped to an Account Family. " 84 | + "Mapping accounts to an account family is necessary for invoicing. These are the unmapped accounts:

" 85 | + "

" + account_list.replace(/\n/i, '
') + "

" 86 | }, 87 | Text: { 88 | Charset: "UTF-8", 89 | Data: "Hello,\n\nSome accounts were found in CloudCheckr which are not mapped to an Account Family. " 90 | + "Mapping accounts to an account family is necessary for invoicing. These are the unmapped accounts:" 91 | + "\n\n" + account_list 92 | } 93 | }, 94 | Subject: { 95 | Charset: "UTF-8", 96 | Data: "Unmapped CloudCheckr Accounts Found" 97 | } 98 | }, 99 | Source: process.env.sourceAddr 100 | }; 101 | ses.sendEmail(params, function(err, data) { 102 | if (err) console.log(err, err.stack); // an error occurred 103 | else console.log(data); // successful response 104 | }); 105 | } 106 | } 107 | }); 108 | } catch (e) { 109 | console.log(e); 110 | callback(1); 111 | } 112 | } 113 | 114 | exports.handler = (event, context, callback) => { 115 | "use strict"; 116 | 117 | var params = { 118 | Names: [ 119 | 'cc_admin_access_key' 120 | ], 121 | WithDecryption: true 122 | }; 123 | 124 | ssm.getParameters(params, function(err, data) { 125 | if (err) { 126 | console.log(err, err.stack); // an error occurred 127 | callback(err); 128 | } else if (data['Parameters'] == undefined) { 129 | console.log(data); 130 | callback("SSM was able to reach parameter store, but no parameter was found for the access key."); 131 | } else { 132 | cc_admin_access_key = data['Parameters'][0]['Value']; 133 | processEvent(event, context, callback); 134 | } 135 | }); 136 | }; 137 | -------------------------------------------------------------------------------- /Onboarding/UserMigration/output1.txt: -------------------------------------------------------------------------------- 1 | Script started on Mon Mar 5 21:21:46 2018 2 | [?1034hbash-3.2$ python3 migrate_users.py qa 00000000 api 00000000 3 | Migrate Users and Groups from qa to api 4 | 5 | Migration is between different regions 6 | Grabbed Original Group List 7 | Created Group: Nate Group in api with id: 019b93ac-b2d7-49f1-94bf-470b3c38e35d 8 | Created Group: Blank Group in api with id: ecf9f2b9-8de1-4f04-ad49-e72ef400052c 9 | Created Group: Mark Group in api with id: b88ca592-0297-46f0-99e6-bf3891eb7a37 10 | Created Group: Alec Group in api with id: 2a40a433-c9fa-46c3-9946-5578e9ffcf94 11 | Finished Creating groups 12 | 13 | Start adding group permissions 14 | Added Group Permissions from 7fcc577c-4f7f-4b2b-8f8b-07a6aa8beaac to 019b93ac-b2d7-49f1-94bf-470b3c38e35d for the account MasterPayer 15 | Added Group Permissions from 7fcc577c-4f7f-4b2b-8f8b-07a6aa8beaac to 019b93ac-b2d7-49f1-94bf-470b3c38e35d for the account 183698509299 (Aaron Gettings) 16 | Added Group Permissions from 7fcc577c-4f7f-4b2b-8f8b-07a6aa8beaac to 019b93ac-b2d7-49f1-94bf-470b3c38e35d for the account 260172486890 (Aaron Klein) 17 | No accounts permissionsed in this group 9489bed8-c4b2-4049-b9b0-12433b81d8fa 18 | Added Group Permissions from a866d674-a66a-4e8a-a28c-309b23383565 to b88ca592-0297-46f0-99e6-bf3891eb7a37 for the account 557949322966 (CloudCheckr Support) 19 | Added Group Permissions from a866d674-a66a-4e8a-a28c-309b23383565 to b88ca592-0297-46f0-99e6-bf3891eb7a37 for the account 318100514071 (ElishaCCTest) 20 | Added Group Permissions from a866d674-a66a-4e8a-a28c-309b23383565 to b88ca592-0297-46f0-99e6-bf3891eb7a37 for the account 443094636793 (Aaron Klein ()) 21 | Added Group Permissions from a866d674-a66a-4e8a-a28c-309b23383565 to b88ca592-0297-46f0-99e6-bf3891eb7a37 for the account All Accounts 22 | Added Group Permissions from 2e83a4df-41e2-49e5-bda5-da2d77e6d6a3 to 2a40a433-c9fa-46c3-9946-5578e9ffcf94 for the account MasterPayer 23 | Added Group Permissions from 2e83a4df-41e2-49e5-bda5-da2d77e6d6a3 to 2a40a433-c9fa-46c3-9946-5578e9ffcf94 for the account 260172486890 (Aaron Klein) 24 | Finished adding All Groups Permissions 25 | 26 | No users in the group Blank Group 27 | Created the user kevin4@cloudcheckr.com 28 | Created the user nate4@cloudcheckr.com in the group Nate Group 29 | Created the user mark4@cloudcheckr.com in the group Mark Group 30 | Created the user nate3@cloudcheckr.com in the group Nate Group 31 | Created the user kevin3@cloudcheckr.com 32 | Created the user alec3@cloudcheckr.com in the group Alec Group 33 | Created the user mark1@cloudcheckr.com in the group Mark Group 34 | Created the user kevin2@cloudcheckr.com 35 | Created the user alec4@cloudcheckr.com in the group Alec Group 36 | Created the user nate2@cloudcheckr.com in the group Nate Group 37 | Created the user kevin5@cloudcheckr.com 38 | Created the user alec7@cloudcheckr.com in the group Alec Group 39 | Created the user alec1@cloudcheckr.com in the group Alec Group 40 | Created the user alecadminonboarding@cloudcheckr.com 41 | Created the user mark3@cloudcheckr.com in the group Mark Group 42 | Created the user mark2@cloudcheckr.com in the group Mark Group 43 | Created the user nate1@cloudcheckr.com in the group Nate Group 44 | Created the user nate5@cloudcheckr.com in the group Nate Group 45 | Created the user alecadmin@cloudcheckr.com 46 | Created the user kevin1@cloudcheckr.com 47 | Created the user alec5@cloudcheckr.com in the group Alec Group 48 | Created the user nate22@cloudcheckr.com in the group Nate Group 49 | Created the user alec6@cloudcheckr.com in the group Alec Group 50 | Created the user alec2@cloudcheckr.com in the group Alec Group 51 | Created the user mark5@cloudcheckr.com in the group Mark Group 52 | Finished Creating Users 53 | 54 | Start adding user account level permissions 55 | Gave user kevin4@cloudcheckr.com permissions to account MasterPayer 56 | Gave user kevin4@cloudcheckr.com permissions to account 183698509299 (Aaron Gettings) 57 | Gave user kevin4@cloudcheckr.com permissions to account 318100514071 (ElishaCCTest) 58 | Gave user kevin4@cloudcheckr.com permissions to account 260172486890 (Aaron Klein) 59 | Gave user kevin4@cloudcheckr.com permissions to account 443094636793 (Aaron Klein ()) 60 | Gave user kevin3@cloudcheckr.com permissions to account MasterPayer 61 | Gave user kevin3@cloudcheckr.com permissions to account 183698509299 (Aaron Gettings) 62 | Gave user kevin3@cloudcheckr.com permissions to account 318100514071 (ElishaCCTest) 63 | Gave user kevin3@cloudcheckr.com permissions to account 260172486890 (Aaron Klein) 64 | Gave user kevin3@cloudcheckr.com permissions to account 443094636793 (Aaron Klein ()) 65 | Gave user alec3@cloudcheckr.com permissions to account MasterPayer 66 | Gave user alec3@cloudcheckr.com permissions to account 557949322966 (CloudCheckr Support) 67 | Gave user alec3@cloudcheckr.com permissions to account 183698509299 (Aaron Gettings) 68 | Gave user alec3@cloudcheckr.com permissions to account 318100514071 (ElishaCCTest) 69 | Gave user alec3@cloudcheckr.com permissions to account 260172486890 (Aaron Klein) 70 | Gave user alec3@cloudcheckr.com permissions to account 443094636793 (Aaron Klein ()) 71 | Gave user alec3@cloudcheckr.com permissions to account 245990094719 (Aaron Klein) 72 | Gave user alec3@cloudcheckr.com permissions to account All Accounts 73 | Gave user alec3@cloudcheckr.com permissions to account MAV2 74 | Gave user kevin5@cloudcheckr.com permissions to account MasterPayer 75 | Gave user kevin5@cloudcheckr.com permissions to account 183698509299 (Aaron Gettings) 76 | Gave user kevin5@cloudcheckr.com permissions to account 318100514071 (ElishaCCTest) 77 | Gave user kevin5@cloudcheckr.com permissions to account 260172486890 (Aaron Klein) 78 | Gave user kevin5@cloudcheckr.com permissions to account 443094636793 (Aaron Klein ()) 79 | Gave user alec1@cloudcheckr.com permissions to account 557949322966 (CloudCheckr Support) 80 | Gave user alec1@cloudcheckr.com permissions to account 318100514071 (ElishaCCTest) 81 | Gave user kevin1@cloudcheckr.com permissions to account MasterPayer 82 | Gave user kevin1@cloudcheckr.com permissions to account 183698509299 (Aaron Gettings) 83 | Gave user kevin1@cloudcheckr.com permissions to account 318100514071 (ElishaCCTest) 84 | Gave user kevin1@cloudcheckr.com permissions to account 260172486890 (Aaron Klein) 85 | Gave user kevin1@cloudcheckr.com permissions to account 443094636793 (Aaron Klein ()) 86 | Gave user alec2@cloudcheckr.com permissions to account MasterPayer 87 | Gave user alec2@cloudcheckr.com permissions to account 557949322966 (CloudCheckr Support) 88 | Gave user alec2@cloudcheckr.com permissions to account 183698509299 (Aaron Gettings) 89 | Gave user alec2@cloudcheckr.com permissions to account 318100514071 (ElishaCCTest) 90 | Gave user alec2@cloudcheckr.com permissions to account 260172486890 (Aaron Klein) 91 | Gave user alec2@cloudcheckr.com permissions to account 443094636793 (Aaron Klein ()) 92 | Gave user alec2@cloudcheckr.com permissions to account 245990094719 (Aaron Klein) 93 | Gave user alec2@cloudcheckr.com permissions to account All Accounts 94 | 95 | Finished adding user account level permissions 96 | Finished running user-migration script 97 | bash-3.2$ exit 98 | exit 99 | 100 | Script done on Mon Mar 5 21:23:17 2018 101 | --------------------------------------------------------------------------------