|
| 1 | +# Trusted Profiles |
| 2 | + |
| 3 | +In the IBM Cloud, when authenticating with other services such as Cloud |
| 4 | +Object Storage or Secrets Manager, using trusted profiles is a way to |
| 5 | +authenticate without any API keys being used. This eliminates the risk of |
| 6 | +those being leaked or stolen by a malicious user who uses them to access your |
| 7 | +IBM Cloud resources. |
| 8 | + |
| 9 | +You can read more about trusted profiles in the |
| 10 | +[IBM Cloud documentation](https://cloud.ibm.com/docs/account?topic=account-create-trusted-profile). |
| 11 | + |
| 12 | +The samples in this directory show how to use the trusted profile in your code |
| 13 | +using the IBM Cloud SDK that exists for Go, Java, Node, and Python. |
| 14 | + |
| 15 | +If you are using a different programming language, then you can still use |
| 16 | +trusted profiles, but must implement the interaction with |
| 17 | +[IAM to retrieve an access token for a compute resource token](https://cloud.ibm.com/apidocs/iam-identity-token-api#gettoken-crtoken) |
| 18 | +yourself. |
| 19 | + |
| 20 | +Each of the samples then uses the token to list the files in a Cloud Object |
| 21 | +Storage bucket. |
| 22 | + |
| 23 | +Following are the steps to run the sample. Please note that the sample |
| 24 | +requires account permissions to create various resources including those |
| 25 | +related to IAM permissions. |
| 26 | + |
| 27 | +## Setup |
| 28 | + |
| 29 | +To setup the example, you need three things: |
| 30 | + |
| 31 | +1. A Code Engine project |
| 32 | +2. A Cloud Object Storage bucket |
| 33 | +3. A trusted profile that grants access to the Cloud Object Storage bucket |
| 34 | + |
| 35 | +### Creating a Code Engine project |
| 36 | + |
| 37 | +We are using the command line interface here to setup things. If you have not |
| 38 | +used it before, you can directly run it through the |
| 39 | +[IBM Cloud shell](https://cloud.ibm.com/shell). |
| 40 | + |
| 41 | +When running locally, make sure the necessary plugin is installed: |
| 42 | + |
| 43 | +```sh |
| 44 | +ibmcloud plugin install code-engine |
| 45 | +``` |
| 46 | + |
| 47 | +In the IBM Cloud shell, the plugin is already installed, however it makes |
| 48 | +sense to ensure the latest version is installed: |
| 49 | + |
| 50 | +```sh |
| 51 | +ibmcloud plugin update --all --force |
| 52 | +``` |
| 53 | + |
| 54 | +Then you are ready to create a Code Engine project. Here and in the following |
| 55 | +snippets, variables will be used. Feel free to adjust them to your needs, but |
| 56 | +make sure that you use the same value for the same variable in all snippets. |
| 57 | + |
| 58 | +```sh |
| 59 | +REGION=eu-es |
| 60 | +RESOURCE_GROUP=Default |
| 61 | +CE_PROJECT_NAME=trusted-profiles-test |
| 62 | + |
| 63 | +ibmcloud target -r ${REGION} -g ${RESOURCE_GROUP} |
| 64 | +ibmcloud ce project create --name ${CE_PROJECT_NAME} |
| 65 | +``` |
| 66 | + |
| 67 | +### Creating a Cloud Object Storage bucket |
| 68 | + |
| 69 | +For this sample, you can use an existing Cloud Object Storage bucket that |
| 70 | +you already have. If you never used COS, then here is a one-sentence |
| 71 | +introduction: Cloud Object Storage is a managed data service where you can |
| 72 | +store data in files. |
| 73 | + |
| 74 | +With the following commands, you will setup your first COS instance and a |
| 75 | +bucket. First, make sure the CLI plugin is installed: |
| 76 | + |
| 77 | +```sh |
| 78 | +ibmcloud plugin install cos |
| 79 | +``` |
| 80 | + |
| 81 | +The COS bucket uses a random suffix (`31292`) because bucket names must |
| 82 | +be unique across all IBM Cloud customers in a region. Make sure you use |
| 83 | +your own random characters. |
| 84 | + |
| 85 | +```sh |
| 86 | +REGION=eu-es |
| 87 | +RESOURCE_GROUP=Default |
| 88 | +COS_INSTANCE_NAME=my-first-cos |
| 89 | +COS_BUCKET=my-first-bucket-31292 |
| 90 | + |
| 91 | +ibmcloud resource service-instance-create ${COS_INSTANCE_NAME} cloud-object-storage standard global -g ${RESOURCE_GROUP} -d premium-global-deployment-iam |
| 92 | +COS_INSTANCE_ID=$(ibmcloud resource service-instance ${COS_INSTANCE_NAME} --crn 2>/dev/null | grep ':cloud-object-storage:') |
| 93 | +ibmcloud cos config crn --crn ${COS_INSTANCE_ID} --force |
| 94 | +ibmcloud cos bucket-create --bucket ${COS_BUCKET} --class smart --ibm-service-instance-id ${COS_INSTANCE_ID} --region ${REGION} |
| 95 | +``` |
| 96 | + |
| 97 | +To have content in the bucket, let's store a sample text file: |
| 98 | + |
| 99 | +```sh |
| 100 | +echo Hello World >helloworld.txt |
| 101 | +ibmcloud cos object-put --region ${REGION} --bucket ${COS_BUCKET} --key helloworld.txt --body helloworld.txt |
| 102 | +``` |
| 103 | + |
| 104 | +### Creating a trusted profile that grants a Code Engine Job access to your COS bucket |
| 105 | + |
| 106 | +In this step, we are creating a Trusted Profile which grants read access to |
| 107 | +your COS bucket to a Job called `list-cos-files` in your Code Engine project. |
| 108 | + |
| 109 | +The Job itself, we will create later. |
| 110 | + |
| 111 | +```sh |
| 112 | +REGION=eu-es |
| 113 | +RESOURCE_GROUP=Default |
| 114 | +COS_INSTANCE_NAME=my-first-cos |
| 115 | +COS_BUCKET=my-first-bucket-31292 |
| 116 | +CE_PROJECT_NAME=trusted-profiles-test |
| 117 | +JOB_NAME=list-cos-files |
| 118 | +TRUSTED_PROFILE_NAME=code-engine-cos-access |
| 119 | + |
| 120 | +CE_PROJECT_CRN=$(ibmcloud resource service-instance ${CE_PROJECT_NAME} --location ${REGION} -g ${RESOURCE_GROUP} --crn 2>/dev/null | grep ':codeengine:') |
| 121 | +COS_INSTANCE_ID=$(ibmcloud resource service-instance ${COS_INSTANCE_NAME} --crn 2>/dev/null | grep ':cloud-object-storage:') |
| 122 | + |
| 123 | +ibmcloud iam trusted-profile-create ${TRUSTED_PROFILE_NAME} |
| 124 | +ibmcloud iam trusted-profile-link-create ${TRUSTED_PROFILE_NAME} --name ce-job-${JOB_NAME} --cr-type CE --link-crn ${CE_PROJECT_CRN} --link-component-type job --link-component-name ${JOB_NAME} |
| 125 | +ibmcloud iam trusted-profile-policy-create ${TRUSTED_PROFILE_NAME} --roles "Content Reader" --service-name cloud-object-storage --service-instance ${COS_INSTANCE_ID} --resource-type bucket --resource ${COS_BUCKET} |
| 126 | +``` |
| 127 | + |
| 128 | +## Running the sample |
| 129 | + |
| 130 | +To run the sample, we will now create the Code Engine Job pointing to the |
| 131 | +sources in this repository. Feel free to use `go`, `java`, `node` or |
| 132 | +`python` as value for the `PROGRAMMING_LANGUAGE` variable. |
| 133 | + |
| 134 | +```sh |
| 135 | +REGION=eu-es |
| 136 | +COS_BUCKET=my-first-bucket-31292 |
| 137 | +JOB_NAME=list-cos-files |
| 138 | +PROGRAMMING_LANGUAGE=node |
| 139 | +TRUSTED_PROFILE_NAME=code-engine-cos-access |
| 140 | + |
| 141 | +ibmcloud ce job create --name ${JOB_NAME} \ |
| 142 | + --build-source https://github.com/IBM/CodeEngine \ |
| 143 | + --build-context-dir trusted-profiles/${PROGRAMMING_LANGUAGE} \ |
| 144 | + --trusted-profiles-enabled true \ |
| 145 | + --env COS_REGION=${REGION} \ |
| 146 | + --env COS_BUCKET=${COS_BUCKET} \ |
| 147 | + --env TRUSTED_PROFILE_NAME=${TRUSTED_PROFILE_NAME} |
| 148 | +``` |
| 149 | + |
| 150 | +Code Engine will setup the Job and as part of that runs a build of the chosen |
| 151 | +source. The output is a container image that it pushes to a Container Registry |
| 152 | +namespace that it creates for your project. Once that completed, your Job is |
| 153 | +ready to be run: |
| 154 | + |
| 155 | +```sh |
| 156 | +JOB_NAME=list-cos-files |
| 157 | + |
| 158 | +ibmcloud ce jobrun submit --job ${JOB_NAME} --name ${JOB_NAME}-run-1 |
| 159 | +ibmcloud ce jobrun logs --name ${JOB_NAME}-run-1 --follow |
| 160 | +``` |
| 161 | + |
| 162 | +If everything has been setup correctly, the JobRun logs will show the number |
| 163 | +of items it found and their keys, in case you set up the sample bucket above, |
| 164 | +then it will be just one item called helloworld.txt. |
| 165 | + |
| 166 | +## Code Review |
| 167 | + |
| 168 | +All of the four samples use the language-specific IBM Cloud SDK. Those define |
| 169 | +an `Authenticator` interface and provide the `ContainerAuthenticator` |
| 170 | +implementation. When instantiating the `ContainerAuthenticator`, you must |
| 171 | +provide the identifier or name of trusted profile. The sample job from above |
| 172 | +uses the name which is defined as `TRUSTED_PROFILE_NAME` environment variable |
| 173 | +on the Code Engine Job. |
| 174 | + |
| 175 | +The `Authenticator` has an `authenticate` method that augments an existing |
| 176 | +HTTP request object with the necessary `Authorization` header. Under the |
| 177 | +covers, the `ContainerAuthenticator` for that purpose reaches out to |
| 178 | +[IAM to retrieve an access token for a compute resource token](https://cloud.ibm.com/apidocs/iam-identity-token-api#gettoken-crtoken). |
| 179 | + |
| 180 | +The `ContainerAuthenticator` will also automatically manage the refresh of the |
| 181 | +token. |
| 182 | + |
| 183 | +The sample code authenticates a request against the Cloud Object Storage API |
| 184 | +to list the items in a bucket. The response is parsed and printed. |
0 commit comments