Skip to content

Commit

Permalink
feat: add support for new ContainerAuthenticator (#151)
Browse files Browse the repository at this point in the history
This PR adds an authenticator and token manager for the new "container" flavor of authentication. This style retrieves a compute resource token from the file system and uses that to retrieve an IAM access token, which is used to authenticate with the service.

As part of this PR, I refactored the authenticators to match the refactoring in the token manager (moving out IAM specific functionality into a shared class).
  • Loading branch information
dpopp07 committed Aug 10, 2021
1 parent 796a4eb commit b01c011
Show file tree
Hide file tree
Showing 23 changed files with 923 additions and 83 deletions.
58 changes: 45 additions & 13 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "package-lock.json|^.secrets.baseline$",
"lines": null
},
"generated_at": "2021-08-03T20:56:36Z",
"generated_at": "2021-08-05T20:39:19Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -70,31 +70,31 @@
"hashed_secret": "91dfd9ddb4198affc5c194cd8ce6d338fde470e2",
"is_secret": false,
"is_verified": false,
"line_number": 56,
"line_number": 57,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "47fcf185ee7e15fe05cae31fbe9e4ebe4a06a40d",
"is_secret": false,
"is_verified": false,
"line_number": 121,
"line_number": 122,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "24c3d19b8d127fe8f7274108156a718ec56fc6e6",
"is_secret": false,
"is_verified": false,
"line_number": 135,
"line_number": 136,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "32e8612d8ca77c7ea8374aa7918db8e5df9252ed",
"is_secret": false,
"is_verified": false,
"line_number": 170,
"line_number": 171,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -114,7 +114,7 @@
"hashed_secret": "32e8612d8ca77c7ea8374aa7918db8e5df9252ed",
"is_secret": false,
"is_verified": false,
"line_number": 58,
"line_number": 59,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -142,31 +142,43 @@
"hashed_secret": "8f4bfc22c4fd7cb884f94ec175ff4a3284a174a1",
"is_secret": false,
"is_verified": false,
"line_number": 90,
"line_number": 69,
"type": "Secret Keyword",
"verified_result": null
},
}
],
"auth/authenticators/iam-request-based-authenticator.ts": [
{
"hashed_secret": "f84f793e0af9ade37c8b927bc5091e98f35bf821",
"is_secret": false,
"is_verified": false,
"line_number": 92,
"line_number": 78,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "45c43fe97e3a06ab078b0eeff6fbe622cc417a25",
"is_secret": false,
"is_verified": false,
"line_number": 107,
"line_number": 91,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "99833a8b234b57b886a9aef1dba187fdd7ceece8",
"is_secret": false,
"is_verified": false,
"line_number": 109,
"line_number": 93,
"type": "Secret Keyword",
"verified_result": null
}
],
"auth/token-managers/container-token-manager.ts": [
{
"hashed_secret": "184ee1f04a018aa3b897e085516a9b657fea0f6b",
"is_secret": false,
"is_verified": false,
"line_number": 82,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -262,7 +274,7 @@
"hashed_secret": "6947818ac409551f11fbaa78f0ea6391960aa5b8",
"is_secret": false,
"is_verified": false,
"line_number": 47,
"line_number": 48,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -349,6 +361,16 @@
"verified_result": null
}
],
"test/unit/container-authenticator.test.js": [
{
"hashed_secret": "5c5a15a8b0b3e154d77746945e563ba40100681b",
"is_secret": false,
"is_verified": false,
"line_number": 19,
"type": "Secret Keyword",
"verified_result": null
}
],
"test/unit/cp4d-authenticator.test.js": [
{
"hashed_secret": "85dd3fb12cb0dcae03f1bba6fb61f4edd90d986d",
Expand Down Expand Up @@ -422,7 +444,17 @@
"hashed_secret": "945db841c03e42eef2f3d0a4ff310e2f3b3e59ec",
"is_secret": false,
"is_verified": false,
"line_number": 78,
"line_number": 77,
"type": "Secret Keyword",
"verified_result": null
}
],
"test/unit/iam-request-based-authenticator.test.js": [
{
"hashed_secret": "43ed4c2d8375dfc89e3dc8c917f404b9481d355b",
"is_secret": false,
"is_verified": false,
"line_number": 5,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
51 changes: 51 additions & 0 deletions Authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ The node-sdk-core project supports the following types of authentication:
- Bearer Token
- Identity and Access Management (IAM)
- Cloud Pak for Data
- Container
- No Authentication

The SDK user configures the appropriate type of authentication for use with service instances.
Expand Down Expand Up @@ -171,6 +172,56 @@ import { getAuthenticatorFromEnvironment } from 'ibm-cloud-sdk-core';
const cp4dAuthenticator = getAuthenticatorFromEnvironment('my-service');
```

## Container
The `ContainerAuthenticator` is intended to be used by application code
running inside a compute resource managed by the IBM Kubernetes Service (IKS)
in which a secure compute resource token (CR token) has been stored in a file
within the compute resource's local file system.
The CR token is similar to an IAM apikey except that it is managed automatically by
the compute resource provider (IKS).
This allows the application developer to:
- avoid storing credentials in application code, configuraton files or a password vault
- avoid managing or rotating credentials

The `ContainerAuthenticator` will retrieve the CR token from
the compute resource in which the application is running, and will then perform
the necessary interactions with the IAM token service to obtain an IAM access token
using the IAM "get token" operation with grant-type `cr-token`.
The authenticator will repeat these steps to obtain a new IAM access token when the
current access token expires.
The IAM access token is added to each outbound request in the `Authorization` header in the form:
```
Authorization: Bearer <IAM-access-token>
```

### Properties
- crTokenFilename: (optional) The name of the file containing the injected CR token value. If not specified, then `/var/run/secrets/tokens/vault-token` is used as the default value. The application must have `read` permissions on the file containing the CR token value.
- iamProfileName: (optional) The name of the linked trusted IAM profile to be used when obtaining the IAM access token (a CR token might map to multiple IAM profiles). One of `iamProfileName` or `iamProfileId` must be specified.
- iamProfileId: (optional) The ID of the linked trusted IAM profile to be used when obtaining the IAM access token (a CR token might map to multiple IAM profiles). One of `iamProfileName` or `iamProfileId` must be specified.
- url: (optional) The URL representing the IAM token service endpoint. If not specified, a suitable default value is used.
- clientId/clientSecret: (optional) The `clientId` and `clientSecret` fields are used to form a "basic auth" Authorization header for interactions with the IAM token server. If neither field is specified, then no Authorization header will be sent with token server requests. These fields are optional, but must be specified together.
- disableSslVerification: (optional) A flag that indicates whether verificaton of the server's SSL certificate should be disabled or not. The default value is `false`.
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests made to the IAM token service.

### Programming example
```js
import { ContainerAuthenticator } from 'ibm-cloud-sdk-core';

const authenticator = new ContainerAuthenticator({
iamProfileName: '{profile-name}',
});
```

### External configuration example
```js
import { getAuthenticatorFromEnvironment } from 'ibm-cloud-sdk-core';

// env vars
// MY_SERVICE_AUTH_TYPE=container
// MY_SERVICE_IAM_PROFILE_ID=my_profile_name
const containerAuthenticator = getAuthenticatorFromEnvironment('my-service');
```

## No Auth Authentication
The `NoAuthAuthenticator` is a placeholder authenticator which performs no actual authentication function. It can be used in situations where authentication needs to be bypassed, perhaps while developing or debugging an application or service.

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ This library provides a set of Authenticators used to authenticate requests from
- Bearer Token
- IAM
- CP4D
- Container

There are two ways to create an authenticator:
1. Creating an instance and providing credentials programmatically
Expand Down
116 changes: 116 additions & 0 deletions auth/authenticators/container-authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* Copyright 2021 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.
*/

import { ContainerTokenManager } from '../token-managers';
import { IamRequestOptions, IamRequestBasedAuthenticator } from './iam-request-based-authenticator';

/** Configuration options for IAM authentication. */
export interface Options extends IamRequestOptions {
/** The file containing the compute resource token. */
crTokenFilename?: string;

/** The IAM profile name associated with the compute resource token. */
iamProfileName?: string;

/** The IAM profile ID associated with the compute resource token. */
iamProfileId?: string;
}

/**
* The [[ContainerAuthenticator]] will read a compute resource token from the file system
* and use this value to obtain a bearer token from the IAM token server. When the bearer
* token expires, a new token is obtained from the token server.
*
* The bearer token will be sent as an Authorization header in the form:
*
* Authorization: Bearer <bearer-token>
*/
export class ContainerAuthenticator extends IamRequestBasedAuthenticator {
protected tokenManager: ContainerTokenManager;

private crTokenFilename: string;

private iamProfileName: string;

private iamProfileId: string;

/**
*
* Create a new [[ContainerAuthenticator]] instance.
*
* @param {object} options Configuration options for IAM authentication.
* @param {string} [options.crTokenFilename] The file containing the compute resource token.
* @param {string} [options.iamProfileName] The IAM profile name associated with the compute resource token.
* @param {string} [options.iamProfileId] The IAM profile ID associated with the compute resource token.
* @param {boolean} [options.disableSslVerification] A flag that indicates
* whether verification of the token server's SSL certificate should be
* disabled or not
* @param {string} [options.url] for HTTP token requests.
* @param {object<string, string>} options.headers to be sent with every
* @param {string} [options.clientId] The `clientId` and `clientSecret` fields are used to form a "basic"
* authorization header for IAM token requests.
* @param {string} [options.clientSecret] The `clientId` and `clientSecret` fields are used to form a "basic"
* authorization header for IAM token requests.
* @param {string} [options.scope] The "scope" parameter to use when fetching the bearer token from the
* IAM token server.
* @throws {Error} When the configuration options are not valid.
*/
constructor(options: Options) {
super(options);

// the param names are shared between the authenticator and the token
// manager so we can just pass along the options object
// the token manager will also handle the validation of required options
this.tokenManager = new ContainerTokenManager(options);

this.crTokenFilename = options.crTokenFilename;
this.iamProfileName = options.iamProfileName;
this.iamProfileId = options.iamProfileId;
}

/**
* Setter for the filename of the compute resource token.
* @param {string} scope A string containing a path to the CR token file
*/
public setCrTokenFilename(crTokenFilename: string): void {
this.crTokenFilename = crTokenFilename;

// update properties in token manager
this.tokenManager.setCrTokenFilename(crTokenFilename);
}

/**
* Setter for the "profile_name" parameter to use when fetching the bearer token from the IAM token server.
* @param {string} scope A string that makes up the iamProfileName parameter
*/
public setIamProfileName(iamProfileName: string): void {
this.iamProfileName = iamProfileName;

// update properties in token manager
this.tokenManager.setIamProfileName(iamProfileName);
}

/**
* Setter for the "profile_id" parameter to use when fetching the bearer token from the IAM token server.
* @param {string} scope A string that makes up the iamProfileId parameter
*/
public setIamProfileId(iamProfileId: string): void {
this.iamProfileId = iamProfileId;

// update properties in token manager
this.tokenManager.setIamProfileId(iamProfileId);
}
}
Loading

0 comments on commit b01c011

Please sign in to comment.