Skip to content

Commit

Permalink
Kubernetes: lookup cluster config from google api when using GKE (bac…
Browse files Browse the repository at this point in the history
…kstage#4844)

* Restructure config; add GKE cluster locator

Signed-off-by: mclarke <mclarke@spotify.com>

* PR feedback

Signed-off-by: mclarke <mclarke@spotify.com>

* fix region typo

Signed-off-by: mclarke <mclarke@spotify.com>

* replace config api call with clusters endpoint

Signed-off-by: mclarke <mclarke@spotify.com>

* missed tsc error

Signed-off-by: mclarke <mclarke@spotify.com>

* doc tweak

Signed-off-by: mclarke <mclarke@spotify.com>
  • Loading branch information
mclarke47 authored Mar 8, 2021
1 parent 8e15b19 commit 9581ff0
Show file tree
Hide file tree
Showing 20 changed files with 710 additions and 142 deletions.
48 changes: 48 additions & 0 deletions .changeset/shaggy-islands-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
'@backstage/plugin-kubernetes': minor
'@backstage/plugin-kubernetes-backend': minor
---

Restructure configuration; Add GKE cluster locator

Config migration

1. `kubernetes.clusters` is now at `kubernetes.clusterLocatorMethods[].clusters` when the `clusterLocatorMethod` is of `type: 'config''`
2. `kubernetes.serviceLocatorMethod` is now an object. `multiTenant` is the only valid `type` currently

Old config example:

```yaml
kubernetes:
serviceLocatorMethod: 'multiTenant'
clusterLocatorMethods:
- 'config'
clusters:
- url: http://127.0.0.1:9999
name: minikube
authProvider: 'serviceAccount'
serviceAccountToken:
$env: K8S_MINIKUBE_TOKEN
- url: http://127.0.0.2:9999
name: aws-cluster-1
authProvider: 'aws'
```
New config example:
```yaml
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- url: http://127.0.0.1:9999
name: minikube
authProvider: 'serviceAccount'
serviceAccountToken:
$env: K8S_MINIKUBE_TOKEN
- url: http://127.0.0.2:9999
name: aws-cluster-1
authProvider: 'aws'
```
7 changes: 4 additions & 3 deletions app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,11 @@ lighthouse:
baseUrl: http://localhost:3003

kubernetes:
serviceLocatorMethod: 'multiTenant'
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- 'config'
clusters: []
- type: 'config'
clusters: []

kafka:
clientId: backstage
Expand Down
79 changes: 60 additions & 19 deletions docs/features/kubernetes/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@ The following is a full example entry in `app-config.yaml`:

```yaml
kubernetes:
serviceLocatorMethod: 'multiTenant'
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- 'config'
clusters:
- url: http://127.0.0.1:9999
name: minikube
authProvider: 'serviceAccount'
serviceAccountToken:
$env: K8S_MINIKUBE_TOKEN
- url: http://127.0.0.2:9999
name: gke-cluster-1
authProvider: 'google'
- type: 'config'
clusters:
- url: http://127.0.0.1:9999
name: minikube
authProvider: 'serviceAccount'
serviceAccountToken:
$env: K8S_MINIKUBE_TOKEN
- url: http://127.0.0.2:9999
name: aws-cluster-1
authProvider: 'aws'
- type: 'gke'
projectId: 'gke-clusters'
region: 'europe-west1'
```
### `serviceLocatorMethod`
Expand All @@ -44,26 +48,28 @@ Currently, the only valid value is:

This is an array used to determine where to retrieve cluster configuration from.

Currently, the only valid cluster locator method is:
Valid cluster locator methods are:

- `config` - This cluster locator method will read cluster information from your
app-config (see below).
#### `config`

### `clusters`
This cluster locator method will read cluster information from your app-config
(see below).

##### `clusters`

Used by the `config` cluster locator method to construct Kubernetes clients.

### `clusters.\*.url`
##### `clusters.\*.url`

The base URL to the Kubernetes control plane. Can be found by using the
"Kubernetes master" result from running the `kubectl cluster-info` command.

### `clusters.\*.name`
##### `clusters.\*.name`

A name to represent this cluster, this must be unique within the `clusters`
array. Users will see this value in the Service Catalog Kubernetes plugin.

### `clusters.\*.authProvider`
##### `clusters.\*.authProvider`

This determines how the Kubernetes client authenticates with the Kubernetes
cluster. Valid values are:
Expand All @@ -73,7 +79,7 @@ cluster. Valid values are:
| `serviceAccount` | This will use a Kubernetes [service account](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/) to access the Kubernetes API. When this is used the `serviceAccountToken` field should also be set. |
| `google` | This will use a user's Google auth token from the [Google auth plugin](https://backstage.io/docs/auth/) to access the Kubernetes API. |

### `clusters.\*.serviceAccountToken` (optional)
##### `clusters.\*.serviceAccountToken` (optional)

The service account token to be used when using the `serviceAccount` auth
provider. You could get the service account token with:
Expand All @@ -85,6 +91,38 @@ kubectl -n <NAMESPACE> get secret $(kubectl -n <NAMESPACE> get sa <SERVICE_ACCOU
| base64 --decode
```

#### `gke`

This cluster locator is designed to work with Kubernetes clusters running in
[GKE][1]. It will configure the Kubernetes backend plugin to make requests to
clusters running within a Google Cloud project.

This cluster locator method will use the `google` authentication mechanism.

The Google Cloud service account to use can be configured through the
`GOOGLE_APPLICATION_CREDENTIALS` environment variable. Consult the [Google Cloud
docs][2] for more information.

For example:

```yaml
- type: 'gke'
projectId: 'gke-clusters'
region: 'europe-west1'
```

Will configure the Kubernetes plugin to connect to all GKE clusters in the
project `gke-clusters` in the region `europe-west1`.

##### `projectId`

The Google Cloud project to look for Kubernetes clusters in.

##### `region` (optional)

The Google Cloud region to look for Kubernetes clusters in. Defaults to all
regions.

### Role Based Access Control

The current RBAC permissions required are read-only cluster wide, for the
Expand Down Expand Up @@ -135,3 +173,6 @@ for more info.
```yaml
'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end'
```

[1]: https://cloud.google.com/kubernetes-engine
[2]: https://cloud.google.com/docs/authentication/production#linux-or-macos
1 change: 1 addition & 0 deletions plugins/kubernetes-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@backstage/backend-common": "^0.5.5",
"@backstage/catalog-model": "^0.7.3",
"@backstage/config": "^0.1.3",
"@google-cloud/container": "^2.2.0",
"@kubernetes/client-node": "^0.13.2",
"@types/express": "^4.17.6",
"aws4": "^1.11.0",
Expand Down
15 changes: 7 additions & 8 deletions plugins/kubernetes-backend/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ClusterLocatorMethod } from './src/types';

export interface Config {
kubernetes?: {
serviceLocatorMethod: 'multiTenant';
clusterLocatorMethods: 'config'[];
clusters: {
url: string;
name: string;
serviceAccountToken: string | undefined;
authProvider: 'aws' | 'google' | 'serviceAccount';
}[];
serviceLocatorMethod: {
type: 'multiTenant';
};
clusterLocatorMethods: ClusterLocatorMethod[];
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ describe('ConfigClusterLocator', () => {
clusters: [],
});

const sut = ConfigClusterLocator.fromConfig(
config.getConfigArray('clusters'),
);
const sut = ConfigClusterLocator.fromConfig(config);

const result = await sut.getClusters();

Expand All @@ -44,9 +42,7 @@ describe('ConfigClusterLocator', () => {
],
});

const sut = ConfigClusterLocator.fromConfig(
config.getConfigArray('clusters'),
);
const sut = ConfigClusterLocator.fromConfig(config);

const result = await sut.getClusters();

Expand Down Expand Up @@ -77,9 +73,7 @@ describe('ConfigClusterLocator', () => {
],
});

const sut = ConfigClusterLocator.fromConfig(
config.getConfigArray('clusters'),
);
const sut = ConfigClusterLocator.fromConfig(config);

const result = await sut.getClusters();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier {
this.clusterDetails = clusterDetails;
}

static fromConfig(config: Config[]): ConfigClusterLocator {
static fromConfig(config: Config): ConfigClusterLocator {
// TODO: Add validation that authProvider is required and serviceAccountToken
// is required if authProvider is serviceAccount
return new ConfigClusterLocator(
config.map(c => {
config.getConfigArray('clusters').map(c => {
return {
name: c.getString('name'),
url: c.getString('url'),
Expand Down
Loading

0 comments on commit 9581ff0

Please sign in to comment.