diff --git a/arboretum/common/ibm_constants.py b/arboretum/common/ibm_constants.py index 9015273b..ef1afeaa 100644 --- a/arboretum/common/ibm_constants.py +++ b/arboretum/common/ibm_constants.py @@ -19,3 +19,6 @@ # IAM token API KEY grant type IAM_API_KEY_GRANT_TYPE = 'urn:ibm:params:oauth:grant-type:apikey' + +# IBM Cloud containers API base URL +IC_CONTAINERS_BASE_URL = 'https://containers.cloud.ibm.com' diff --git a/arboretum/ibm_cloud/README.md b/arboretum/ibm_cloud/README.md index fb9def86..0cc3949c 100644 --- a/arboretum/ibm_cloud/README.md +++ b/arboretum/ibm_cloud/README.md @@ -17,7 +17,51 @@ to include the fetchers and checks from this library in your downstream project. ## Fetchers -Fetchers coming soon... +### Cluster List + +* Class: [ClusterListFetcher][fetch-cluster-list] +* Purpose: Write the list of IBM Cloud clusters to the evidence locker. +* Behavior: Access [IBM Cloud API][ibm-cloud-api] and save the list of clusters bound with specified account. +* Configuration elements: + * `org.ibm_cloud.accounts` + * Required + * List of accounts (string) + * Each account is an arbitrary name describing the IBM Cloud account. It is used to match to the token provided in the + credentials file in order for the fetcher to retrieve content from IBM Cloud for that account. +* Example (required) configuration: + + ```json + { + "org": { + "ibm_cloud": { + "accounts": ["myaccount1"] + } + } + } + ``` + +* Required credentials: + * `ibm_cloud` credentials with read/view permissions are needed for this fetcher to successfully retrieve the evidence. + * `XXX_api_key`: API key string for account `XXX`. + * Example credential file entry: + + ```ini + [ibm_cloud] + acct_a_api_key=your-ibm-cloud-api-key-for-acct-a + acct_b_api_key=your-ibm-cloud-api-key-for-acct-b + ``` + + * NOTE: API keys can be generated using the [IBM Cloud CLI][ic-api-key-create] or [IBM Cloud Console][ibm-cloud-gen-api-console]. Example to create an API key with IBM Cloud CLI is: + + ```sh + ibmcloud iam api-key-create your-iks-api-key-for-acct-x + ``` + +* Import statement: + + ```python + from arboretum.ibm_cloud.fetchers.fetch_cluster_list import ClusterListFetcher + ``` ## Checks @@ -26,3 +70,7 @@ Checks coming soon... [auditree-framework]: https://github.com/ComplianceAsCode/auditree-framework [auditree-framework documentation]: https://complianceascode.github.io/auditree-framework/ [usage]: https://github.com/ComplianceAsCode/auditree-arboretum#usage +[ic-api-key-create]: https://cloud.ibm.com/docs/cli/reference/ibmcloud?topic=cloud-cli-ibmcloud_commands_iam#ibmcloud_iam_api_key_create +[fetch-cluster-list]: https://github.com/ComplianceAsCode/auditree-arboretum/blob/main/arboretum/ibm_cloud/fetchers/fetch_cluster_list.py +[ibm-cloud-api]: https://containers.cloud.ibm.com/ +[ibm-cloud-gen-api-console]: https://cloud.ibm.com/docs/account?topic=account-userapikey#create_user_key \ No newline at end of file diff --git a/arboretum/ibm_cloud/fetchers/fetch_cluster_list.py b/arboretum/ibm_cloud/fetchers/fetch_cluster_list.py new file mode 100644 index 00000000..37800a0e --- /dev/null +++ b/arboretum/ibm_cloud/fetchers/fetch_cluster_list.py @@ -0,0 +1,68 @@ +# -*- mode:python; coding:utf-8 -*- +# Copyright (c) 2020 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""IBM Cloud cluster list fetcher.""" + +import json + +from arboretum.common.iam_ibm_utils import get_tokens +from arboretum.common.ibm_constants import IC_CONTAINERS_BASE_URL + +from compliance.evidence import DAY, RawEvidence, store_raw_evidence +from compliance.fetch import ComplianceFetcher + + +class ClusterListFetcher(ComplianceFetcher): + """Fetch the list of IBM Cloud clusters.""" + + @classmethod + def setUpClass(cls): + """Initialize the fetcher object with configuration settings.""" + cls.config.add_evidences( + [ + RawEvidence( + 'cluster_list.json', + 'ibm_cloud', + DAY, + 'IBM Cloud cluster list inventory' + ) + ] + ) + headers = {'Accept': 'application/json'} + cls.session(IC_CONTAINERS_BASE_URL, **headers) + + return cls + + @store_raw_evidence('ibm_cloud/cluster_list.json') + def fetch_cluster_list(self): + """Fetch IBM Cloud cluster list.""" + accounts = self.config.get('org.ibm_cloud.accounts') + cluster_list = {} + for account in accounts: + cluster_list[account] = self._get_cluster_list(account) + return json.dumps(cluster_list) + + def _get_cluster_list(self, account): + + # get credential for the account + api_key = getattr(self.config.creds['ibm_cloud'], f'{account}_api_key') + access_token, _ = get_tokens(api_key) + # get cluster list + # https://cloud.ibm.com/apidocs/kubernetes#getclusters + self.session().headers.update( + {'Authorization': f'Bearer {access_token}'} + ) + resp = self.session().get('/global/v1/clusters') + resp.raise_for_status() + return resp.json()