Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(VpcInstanceAuthenticator): add support for new VPC authentication flow #172

Merged
merged 17 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 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-10-20T21:45:37Z",
"generated_at": "2021-10-27T20:42:11Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -78,15 +78,15 @@
"hashed_secret": "98635b2eaa2379f28cd6d72a38299f286b81b459",
"is_secret": false,
"is_verified": false,
"line_number": 334,
"line_number": 430,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "47fcf185ee7e15fe05cae31fbe9e4ebe4a06a40d",
"is_secret": false,
"is_verified": false,
"line_number": 372,
"line_number": 468,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -276,7 +276,7 @@
"hashed_secret": "6947818ac409551f11fbaa78f0ea6391960aa5b8",
"is_secret": false,
"is_verified": false,
"line_number": 48,
"line_number": 49,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
104 changes: 100 additions & 4 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 Authentication
- Identity and Access Management (IAM) Authentication
- Container Authentication
- VPC Instance Authentication
- Cloud Pak for Data Authentication
- No Authentication

Expand All @@ -14,12 +15,11 @@ which authentication types are supported for that service.

The node-sdk-core allows an authenticator to be specified in one of two ways:
1. programmatically - the SDK user invokes the appropriate function(s) to create an instance of the
desired authenticator and then passes the authenticator instance when constructing an instance of the service client.
desired authenticator and then passes the authenticator instance when constructing an instance of the service.
2. configuration - the SDK user provides external configuration information (in the form of environment variables
or a credentials file) to indicate the type of authenticator, along with the configuration of the necessary properties
for that authenticator.
The SDK user then invokes the configuration-based service client constructor method
to construct an instance of the authenticator and service client that reflect the external configuration information.
for that authenticator. The SDK user then invokes the configuration-based authenticator factory to construct an instance
of the authenticator that is described in the external configuration information.

The sections below will provide detailed information for each authenticator
which will include the following:
Expand Down Expand Up @@ -165,6 +165,15 @@ form:
- url: (optional) The base endpoint URL of the IAM token service.
The default value of this property is the "prod" IAM token service endpoint
(`https://iam.cloud.ibm.com`).
Make sure that you use an IAM token service endpoint that is appropriate for the
location of the service being used by your application.
For example, if you are using an instance of a service in the "production" environment
(e.g. `https://resource-controller.cloud.ibm.com`),
then the default "prod" IAM token service endpoint should suffice.
However, if your application is using an instance of a service in the "staging" environment
(e.g. `https://resource-controller.test.cloud.ibm.com`),
then you would also need to configure the authenticator to use the IAM token service "staging"
endpoint as well (`https://iam.test.cloud.ibm.com`).

- 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
Expand Down Expand Up @@ -257,6 +266,15 @@ One of `iamProfileName` or `iamProfileId` must be specified.
- url: (optional) The base endpoint URL of the IAM token service.
The default value of this property is the "prod" IAM token service endpoint
(`https://iam.cloud.ibm.com`).
Make sure that you use an IAM token service endpoint that is appropriate for the
location of the service being used by your application.
For example, if you are using an instance of a service in the "production" environment
(e.g. `https://resource-controller.cloud.ibm.com`),
then the default "prod" IAM token service endpoint should suffice.
However, if your application is using an instance of a service in the "staging" environment
(e.g. `https://resource-controller.test.cloud.ibm.com`),
then you would also need to configure the authenticator to use the IAM token service "staging"
endpoint as well (`https://iam.test.cloud.ibm.com`).

- clientId/clientSecret: (optional) The `clientId` and `clientSecret` fields are used to form a
"basic auth" Authorization header for interactions with the IAM token service. If neither field
Expand Down Expand Up @@ -314,6 +332,84 @@ const service = ExampleServiceV1.newInstance(options);
```


## VPC Instance Authentication
The `VpcInstanceAuthenticator` is intended to be used by application code
running inside a VPC-managed compute resource (virtual server instance) that has been configured
to use the "compute resource identity" feature.
The compute resource identity feature allows you to assign a trusted IAM profile to the compute resource as its "identity".
This, in turn, allows applications running within the compute resource to take on this identity when interacting with
IAM-secured IBM Cloud services.
This results in a simplified security model that allows the application developer to:
- avoid storing credentials in application code, configuraton files or a password vault
- avoid managing or rotating credentials

The `VpcInstanceAuthenticator` will invoke the appropriate operations on the compute resource's locally-available
VPC Instance Metadata Service to (1) retrieve an instance identity token
and then (2) exchange that instance identity token for an IAM access token.
The authenticator will repeat these steps to obtain a new IAM access token whenever 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

- iamProfileCrn: (optional) the crn of the linked trusted IAM profile to be used when obtaining the IAM access token.

- iamProfileId: (optional) the id of the linked trusted IAM profile to be used when obtaining the IAM access token.

- url: (optional) The VPC Instance Metadata Service's base URL.
The default value of this property is `http://169.254.169.254`, and should not need to be specified in normal situations.

Usage Notes:
1. At most one of `iamProfileCrn` or `iamProfileId` may be specified. The specified value must map
to a trusted IAM profile that has been linked to the compute resource (virtual server instance).

2. If both `iamProfileCrn` and `iamProfileId` are specified, then an error occurs.

3. If neither `iamProfileCrn` nor `iamProfileId` are specified, then the default trusted profile linked to the
compute resource will be used to perform the IAM token exchange.
If no default trusted profile is defined for the compute resource, then an error occurs.


### Programming example
```js
const { VpcInstanceAuthenticator } = require('ibm-cloud-sdk-core');
const ExampleServiceV1 = require('<sdk-package-name>/example-service/v1');

const authenticator = new VpcInstanceAuthenticator({
iamProfileCrn: 'crn:iam-profile-123',
});

const options = {
authenticator,
};

const service = new ExampleServiceV1(options);

// 'service' can now be used to invoke operations.
```

### Configuration example
External configuration:
```
export EXAMPLE_SERVICE_AUTH_TYPE=vpc
export EXAMPLE_SERVICE_IAM_PROFILE_CRN=crn:iam-profile-123
```
Application code:
```js
const ExampleServiceV1 = require('<sdk-package-name>/example-service/v1');

const options = {
serviceName: 'example_service',
};

const service = ExampleServiceV1.newInstance(options);

// 'service' can now be used to invoke operations.
```


## Cloud Pak for Data Authentication
The `CloudPakForDataAuthenticator` will accept a user-supplied username value, along with either a
password or apikey, and will
Expand Down
2 changes: 2 additions & 0 deletions auth/authenticators/authenticator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export class Authenticator implements AuthenticatorInterface {

static AUTHTYPE_NOAUTH = 'noAuth';

static AUTHTYPE_VPC = 'vpc';

static AUTHTYPE_UNKNOWN = 'unknown';

/**
Expand Down
6 changes: 3 additions & 3 deletions auth/authenticators/container-authenticator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class ContainerAuthenticator extends IamRequestBasedAuthenticator {

/**
* Setter for the filename of the compute resource token.
* @param {string} scope A string containing a path to the CR token file
* @param {string} A string containing a path to the CR token file
*/
public setCrTokenFilename(crTokenFilename: string): void {
this.crTokenFilename = crTokenFilename;
Expand All @@ -95,7 +95,7 @@ export class ContainerAuthenticator extends IamRequestBasedAuthenticator {

/**
* 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
* @param {string} A string that makes up the iamProfileName parameter
*/
public setIamProfileName(iamProfileName: string): void {
this.iamProfileName = iamProfileName;
Expand All @@ -106,7 +106,7 @@ export class ContainerAuthenticator extends IamRequestBasedAuthenticator {

/**
* 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
* @param {string} A string that makes up the iamProfileId parameter
*/
public setIamProfileId(iamProfileId: string): void {
this.iamProfileId = iamProfileId;
Expand Down
3 changes: 3 additions & 0 deletions auth/authenticators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* Bearer Token
* Identity and Access Management (IAM)
* Container (IKS, etc)
* VPC Instance
* Cloud Pak for Data
* No Authentication
*
Expand All @@ -36,6 +37,7 @@
* CloudPakForDataAuthenticator: Authenticator for passing CP4D authentication information to service endpoint.
* IAMAuthenticator: Authenticator for passing IAM authentication information to service endpoint.
* ContainerAuthenticator: Authenticator for passing IAM authentication to a service, based on a token living on the container.
* VpcInstanceAuthenticator: Authenticator that uses the VPC Instance Metadata Service API to retrieve an IAM token.
* NoAuthAuthenticator: Performs no authentication. Useful for testing purposes.
*/

Expand All @@ -49,3 +51,4 @@ export { ContainerAuthenticator } from './container-authenticator';
export { NoAuthAuthenticator } from './no-auth-authenticator';
export { IamRequestBasedAuthenticator } from './iam-request-based-authenticator';
export { TokenRequestBasedAuthenticator } from './token-request-based-authenticator';
export { VpcInstanceAuthenticator } from './vpc-instance-authenticator';
108 changes: 108 additions & 0 deletions auth/authenticators/vpc-instance-authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* (C) Copyright IBM Corp. 2021.
*
* 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 { Authenticator } from './authenticator';
import { VpcInstanceTokenManager } from '../token-managers';
import { BaseOptions, TokenRequestBasedAuthenticator } from './token-request-based-authenticator';

/** Configuration options for VpcInstance authentication. */
export interface Options extends BaseOptions {
/** The CRN of the linked trusted IAM profile to be used as the identity of the compute resource */
iamProfileCrn?: string;
/** The ID of the linked trusted IAM profile to be used when obtaining the IAM access token */
iamProfileId?: string;
}

/**
* The [[VpcInstanceAuthenticator]] implements an authentication scheme in which it retrieves an "instance identity token"
* and exchanges that for an IAM access token using the VPC Instance Metadata Service API which is available on the local
* compute resource (VM). The instance identity token is similar to an IAM apikey, except that it is managed automatically
* by the compute resource provider (VPC).
*
* The resulting IAM access token is then added to outbound requests in an Authorization header
*
* Authorization: Bearer <access-token>
*/
export class VpcInstanceAuthenticator extends TokenRequestBasedAuthenticator {
protected tokenManager: VpcInstanceTokenManager;

private iamProfileCrn: string;

private iamProfileId: string;

/**
* Create a new [[VpcInstanceAuthenticator]] instance.
*
* @param {object} [options] Configuration options for VpcInstance authentication.
* @param {string} [options.iamProfileCrn] The CRN of the linked trusted IAM profile to be used as the identity of the compute resource.
* At most one of iamProfileCrn or iamProfileId may be specified.
* If neither one is specified, then the default IAM profile defined for the compute resource will be used.
* @param {string} [options.iamProfileId] The ID of the linked trusted IAM profile to be used when obtaining the IAM access token.
* At most one of iamProfileCrn or iamProfileId may be specified.
* If neither one is specified, then the default IAM profile defined for the compute resource will be used.
* @param {string} [options.url] The VPC Instance Metadata Service's base endpoint URL. Default value: "http://169.254.169.254"
*/
constructor(options: Options) {
// all parameters are optional
options = options || ({} as Options);

super(options);

if (options.iamProfileCrn) {
this.iamProfileCrn = options.iamProfileCrn;
}
if (options.iamProfileId) {
this.iamProfileId = options.iamProfileId;
}

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

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

// update properties in token manager
this.tokenManager.setIamProfileCrn(iamProfileCrn);
}

/**
* Setter for the "profile_id" parameter to use when fetching the bearer token from the IAM token server.
* @param {string} 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);
}

/**
* Returns the authenticator's type ('vpc').
*
* @returns a string that indicates the authenticator's type
*/
// eslint-disable-next-line class-methods-use-this
public authenticationType(): string {
return Authenticator.AUTHTYPE_VPC;
}
}
3 changes: 3 additions & 0 deletions auth/token-managers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* Identity and Access Management (IAM)
* Cloud Pak for Data
* Container (IKS, etc)
* VPC Instance
*
* The token managers sit inside of an authenticator and do the work to retrieve
* tokens where as the authenticators add these tokens to the actual request.
Expand All @@ -29,6 +30,7 @@
* IamTokenManager: Token Manager of IAM via apikey.
* Cp4dTokenManager: Token Manager of CloudPak for data.
* ContainerTokenManager: Token manager of IAM via compute resource token.
* VpcInstanceTokenManager: Token manager of VPC Instance Metadata Service API tokens.
* JwtTokenManager: A class for shared functionality for parsing, storing, and requesting JWT tokens.
*/

Expand All @@ -38,3 +40,4 @@ export { ContainerTokenManager } from './container-token-manager';
export { IamRequestBasedTokenManager, IamRequestOptions } from './iam-request-based-token-manager';
export { JwtTokenManager, JwtTokenManagerOptions } from './jwt-token-manager';
export { TokenManager, TokenManagerOptions } from './token-manager';
export { VpcInstanceTokenManager } from './vpc-instance-token-manager';
Loading