Skip to content

Commit

Permalink
[v16] helm: Add support for jamf_service to the teleport-kube-agent H…
Browse files Browse the repository at this point in the history
…elm chart (#42604)

* Add jamf_service support to the Helm chart

* Add tests for jamf_service

* Remove unnecessary comments

* Update README

* Update values schema

* Update docs

* Commit missing lint files

* Update test snapshots

* Fix Secret tests

* Update docs

* Add support for Jamf API Client Credentials

* Update snapshots

* Unify Jamf password/Client Secret into jamfSecret key in Secret

* Update snapshots

* Add lint files

* Update docs

* Update image version in tests

* Add words to a dictionary

* Apply suggestions from code review

Co-authored-by: Hugo Shaka <hugo.hervieux@goteleport.com>

* Drop support for Jamf username and password auth

* Update image tags

---------

Co-authored-by: Hugo Shaka <hugo.hervieux@goteleport.com>
  • Loading branch information
lcharkiewicz and hugoShaka authored Jun 7, 2024
1 parent 33e4b93 commit dfc0901
Show file tree
Hide file tree
Showing 21 changed files with 933 additions and 47 deletions.
2 changes: 2 additions & 0 deletions docs/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,8 @@
"ioreg",
"isnt",
"isrgrootx",
"jamfapiendpoint",
"jamfclientid",
"javapipeline",
"jetbrains",
"jiraapitoken",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ when running the `teleport-kube-agent` chart.
| Teleport Application service | `app` | [`apps`](#apps) or [`appResources`](#appresources) |
| Teleport Database service | `db` | [`databases`](#databases) or [`databaseResources`](#databaseresources) |
| Teleport Discovery service | `discovery` | [`kubeClusterName`](#kubeclustername) |
| Teleport Jamf service | `jamf` | [`jamfApiEndpoint`](#jamfapiendpoint), [`jamfClientId`](#jamfclientid) |

For example:
```yaml
Expand Down Expand Up @@ -454,6 +455,85 @@ kubernetesDiscovery:
env: testing
```

## `jamfApiEndpoint`

| Type | Default |
|------|---------|
| `string` | `""` |

`jamfApiEndpoint` sets the Jamf Pro API endpoint used for Jamf service.
Example: "https://yourtenant.jamfcloud.com/api".

This setting is required if the chart `roles` contains `jamf`.

## `jamfClientId`

| Type | Default |
|------|---------|
| `string` | `""` |

`jamfClientId` sets the Jamf Pro API Client ID used for Jamf service.

This setting is required if the chart `roles` contains `jamf`.

## `jamfClientSecret`

| Type | Default |
|------|---------|
| `string` | `""` |

`jamfClientSecret` sets the Jamf Pro API client secret used for Jamf service.

This setting is required if the chart `roles` contains `jamf` and `jamfCredentialsSecret.create` is set to `true`.
If you provide your own Kubernetes Secret, this setting can remain unset.

## `jamfCredentialsSecret`

`jamfCredentialsSecret` manages the Kubernetes Secret containing the Jamf API credentials (either Jamf client secret or password).

### `jamfCredentialsSecret.create`

| Type | Default |
|------|---------|
| `bool` | `true` |

`jamfCredentialsSecret.create` controls whether the chart creates the
Kubernetes `Secret` containing the Jamf Pro API Client Secret.
If false, you must create a Kubernetes Secret with the configured name in
the Helm release namespace.

### `jamfCredentialsSecret.name`

| Type | Default |
|------|---------|
| `string` | `"teleport-jamf-api-credentials"` |

`jamfCredentialsSecret.name` is the name of the Kubernetes Secret
containing the Jamf Pro API Client Secret used by the chart.

If `jamfCredentialsSecret.create` is `false`, the chart will not attempt to create the secret itself.
Instead, it will read the value from an existing Kubernetes Secret. `jamfCredentialsSecret.name`
configures the name of this secret. This allows you to configure this secret externally and avoid having a plaintext
Jamf Pro API Client Secret stored in your Teleport chart values.

To create your own Kubernetes Secret containing Jamf Pro API Client Secret, run the command:

```code
$ kubectl --namespace teleport create secret generic my-jamf-secret --from-literal=credential=<replace-with-actual-secret>
```

<Admonition type="note">
The key used for the Jamf Pro API Client Secret inside the secret must be `credential`, as in the command above.
</Admonition>

For example:

```yaml
jamfCredentialsSecret:
create: false
name: my-jamf-secret
```

## `teleportVersionOverride`

| Type | Default |
Expand Down
52 changes: 27 additions & 25 deletions docs/pages/reference/helm-reference/teleport-kube-agent.mdx

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion examples/chart/teleport-kube-agent/.lint/all-v6.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
authToken: auth-token
proxyAddr: proxy.example.com:3080
roles: kube,app,db
roles: kube,app,db,jamf
kubeClusterName: test-kube-cluster-name
labels:
cluster: testing
Expand All @@ -15,6 +15,9 @@ databases:
protocol: "postgres"
labels:
database: staging
jamfApiEndpoint: "testjamf.jamfcloud.com/api"
jamfClientId: teleport-jamf-client-id
jamfClientSecret: secret-jamf-client-secret
annotations:
config:
kubernetes.io/config: "test-annotation"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
authToken: auth-token
proxyAddr: proxy.example.com:3080
roles: jamf
jamfApiEndpoint: "https://testjamf.jamfcloud.com/api"
jamfClientId: teleport-jamf-client-id
jamfCredentialsSecret:
create: false
name: existing-teleport-jamf-secret
6 changes: 6 additions & 0 deletions examples/chart/teleport-kube-agent/.lint/jamf-service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
authToken: auth-token
proxyAddr: proxy.example.com:3080
roles: jamf
jamfApiEndpoint: "https://testjamf.jamfcloud.com/api"
jamfClientId: teleport-jamf-client-id
jamfClientSecret: secret-jamf-client-secret
89 changes: 73 additions & 16 deletions examples/chart/teleport-kube-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ with an existing Teleport cluster:
- Teleport Application access
- Teleport Database access
- Teleport Kubernetes App Discovery
- Teleport Jamf service

To use it, you will need:
- an existing Teleport cluster (at least proxy and auth services)
Expand Down Expand Up @@ -133,14 +134,14 @@ Set the values in the above command as appropriate for your setup.

These are the supported values for the `apps` map:

| Key | Description | Example | Default | Required |
| --- | --- | --- | --- | --- |
| `name` | Name of the app to be accessed | `apps[0].name=grafana` | | Yes |
| `uri` | URI of the app to be accessed | `apps[0].uri=http://localhost:3000` | | Yes |
| `public_addr` | Public address used to access the app | `apps[0].public_addr=grafana.teleport.example.com` | | No |
| `labels.[name]` | Key-value pairs to set against the app for grouping/RBAC | `apps[0].labels.env=local,apps[0].labels.region=us-west-1` | | No |
| `insecure_skip_verify` | Whether to skip validation of TLS certificates presented by backend apps | `apps[0].insecure_skip_verify=true` | `false` | No |
| `rewrite.redirect` | A list of URLs to rewrite to the public address of the app service | `apps[0].rewrite.redirect[0]=https://192.168.1.1` | | No
| Key | Description | Example | Default | Required |
| ---------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------- | ------- | -------- |
| `name` | Name of the app to be accessed | `apps[0].name=grafana` | | Yes |
| `uri` | URI of the app to be accessed | `apps[0].uri=http://localhost:3000` | | Yes |
| `public_addr` | Public address used to access the app | `apps[0].public_addr=grafana.teleport.example.com` | | No |
| `labels.[name]` | Key-value pairs to set against the app for grouping/RBAC | `apps[0].labels.env=local,apps[0].labels.region=us-west-1` | | No |
| `insecure_skip_verify` | Whether to skip validation of TLS certificates presented by backend apps | `apps[0].insecure_skip_verify=true` | `false` | No |
| `rewrite.redirect` | A list of URLs to rewrite to the public address of the app service | `apps[0].rewrite.redirect[0]=https://192.168.1.1` | | No |

You can add multiple apps using `apps[1].name`, `apps[1].uri`, `apps[2].name`, `apps[2].uri` etc.

Expand Down Expand Up @@ -219,14 +220,14 @@ Set the values in the above command as appropriate for your setup.

These are the supported values for the `databases` map:

| Key | Description | Example | Default | Required |
| --- | --- | --- | --- | --- |
| `name` | Name of the database to be accessed | `databases[0].name=aurora` | | Yes |
| `uri` | URI of the database to be accessed | `databases[0].uri=postgres-aurora-instance-1.xxx.us-east-1.rds.amazonaws.com:5432` | | Yes |
| `protocol` | Database protocol | `databases[0].protocol=postgres` | | Yes |
| `description` | Free-form description of the database proxy instance | `databases[0].description='AWS Aurora instance of PostgreSQL 13.0'` | | No |
| `aws.region` | AWS-specific region configuration (only used for RDS/Aurora) | `databases[0].aws.region=us-east-1` | | No |
| `labels.[name]` | Key-value pairs to set against the database for grouping/RBAC | `databases[0].labels.db=postgres-dev,apps[0].labels.region=us-east-1` | | No |
| Key | Description | Example | Default | Required |
| --------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------- | -------- |
| `name` | Name of the database to be accessed | `databases[0].name=aurora` | | Yes |
| `uri` | URI of the database to be accessed | `databases[0].uri=postgres-aurora-instance-1.xxx.us-east-1.rds.amazonaws.com:5432` | | Yes |
| `protocol` | Database protocol | `databases[0].protocol=postgres` | | Yes |
| `description` | Free-form description of the database proxy instance | `databases[0].description='AWS Aurora instance of PostgreSQL 13.0'` | | No |
| `aws.region` | AWS-specific region configuration (only used for RDS/Aurora) | `databases[0].aws.region=us-east-1` | | No |
| `labels.[name]` | Key-value pairs to set against the database for grouping/RBAC | `databases[0].labels.db=postgres-dev,apps[0].labels.region=us-east-1` | | No |

You can add multiple databases using `databases[1].name`, `databases[1].uri`, `databases[1].protocol`,
`databases[2].name`, `databases[2].uri`, `databases[2].protocol` etc.
Expand Down Expand Up @@ -255,6 +256,62 @@ to use for discovery you can use `kubernetesDiscovery` property of the chart.
When discovery is running, `kubeClusterName` should be set in values, since it is used as a name for discovery field and as a target label
for the app service, so it can expose discovered apps.

## Jamf service

To use [Teleport Jamf service](https://goteleport.com/docs/access-controls/device-trust/jamf-integration/),
you will also need:
- provide your Jamf Pro API endpoint
- provide your Jamf Pro API credentials

To install the agent with Jamf API credentials, run:

```sh
$ helm install teleport-kube-agent . \
--create-namespace \
--namespace teleport \
--set roles=jamf \
--set proxyAddr=${PROXY_ENDPOINT?} \
--set authToken=${JOIN_TOKEN?} \
--set jamfApiEndpoint=${JAMF_API_ENDPOINT?} \
--set jamfClientId=${JAMF_CLIENT_ID?} \
--set jamfClientSecret=${JAMF_CLIENT_SECRET?}
```

Set the values in the above command as appropriate for your setup.

The Helm chart will install Secrets by default. To avoid specifying the Jamf API credentials in plain text, it's possible to create a secret containing the password beforehand. To do so, run:

```sh
export JAMF_CLIENT_SECRET=`<jamf client secret> | base64 -w0`
export JAMF_SECRET_NAME=teleport-jamf-api-credentials
export TELEPORT_NAMESPACE=teleport

cat <<EOF > secrets.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: ${JAMF_SECRET_NAME}
namespace: ${TELEPORT_NAMESPACE?}
type: Opaque
data:
jamfSecret: ${JAMF_CLIENT_SECRET?}
EOF

$ kubectl apply -f secret.yaml

$ helm install teleport-kube-agent . \
--create-namespace \
--namespace ${TELEPORT_NAMESPACE?} \
--set roles=jamf \
--set proxyAddr=${PROXY_ENDPOINT?} \
--set authToken=${JOIN_TOKEN?} \
--set jamfApiEndpoint=${JAMF_API_ENDPOINT?} \
--set jamfClientId=${JAMF_CLIENT_ID?} \
--set jamfCredentialsSecret.name=${JAMF_SECRET_NAME?} \
--set jamfCredentialsSecret.create=false
```

## Troubleshooting

If the service for a given role doesn't show up, look into the agent logs with:
Expand Down
10 changes: 10 additions & 0 deletions examples/chart/teleport-kube-agent/templates/_config.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ discovery_service:
enabled: false
{{- end }}

jamf_service:
{{- if contains "jamf" (.Values.roles | toString) }}
enabled: true
api_endpoint: {{ required "jamfApiEndpoint is required in chart values when jamf role is enabled, see README" .Values.jamfApiEndpoint }}
client_id: {{ required "jamfClientId is required in chart values when jamf role is enabled, see README" .Values.jamfClientId }}
client_secret_file: "/etc/teleport-jamf-api-credentials/credential"
{{- else }}
enabled: false
{{- end }}

auth_service:
enabled: false
ssh_service:
Expand Down
15 changes: 15 additions & 0 deletions examples/chart/teleport-kube-agent/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ spec:
name: "teleport-tls-ca"
readOnly: true
{{- end }}
{{- if contains "jamf" (.Values.roles | toString) }}
- mountPath: /etc/teleport-jamf-api-credentials
name: "jamf-api-credentials"
readOnly: true
{{- end }}
{{- if .Values.extraVolumeMounts }}
{{- toYaml .Values.extraVolumeMounts | nindent 8 }}
{{- end }}
Expand Down Expand Up @@ -192,6 +197,11 @@ spec:
name: "teleport-tls-ca"
readOnly: true
{{- end }}
{{- if contains "jamf" (.Values.roles | toString) }}
- mountPath: /etc/teleport-jamf-api-credentials
name: "jamf-api-credentials"
readOnly: true
{{- end }}
{{- if .Values.extraVolumeMounts }}
{{- toYaml .Values.extraVolumeMounts | nindent 8 }}
{{- end }}
Expand All @@ -214,6 +224,11 @@ spec:
secret:
secretName: {{ .Values.tls.existingCASecretName }}
{{- end }}
{{- if contains "jamf" (.Values.roles | toString) }}
- name: "jamf-api-credentials"
secret:
secretName: {{ .Values.jamfCredentialsSecret.name }}
{{- end }}
{{- if .Values.extraVolumes }}
{{- toYaml .Values.extraVolumes | nindent 6 }}
{{- end }}
Expand Down
20 changes: 20 additions & 0 deletions examples/chart/teleport-kube-agent/templates/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,23 @@ stringData:
auth-token: |
{{ coalesce .Values.joinParams.tokenName .Values.authToken }}
{{- end}}

{{- if and (contains "jamf" (.Values.roles | toString)) .Values.jamfCredentialsSecret.create }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.jamfCredentialsSecret.name }}
namespace: {{ .Release.Namespace }}
{{- if .Values.extraLabels.secret }}
labels:
{{- toYaml .Values.extraLabels.secret | nindent 4 }}
{{- end }}
{{- if .Values.annotations.secret }}
annotations:
{{- toYaml .Values.annotations.secret | nindent 4 }}
{{- end }}
type: Opaque
stringData:
credential: {{ required "jamfClientSecret is required in chart values when jamf role is enabled, see README" .Values.jamfClientSecret }}
{{- end}}
15 changes: 15 additions & 0 deletions examples/chart/teleport-kube-agent/templates/statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ spec:
name: "teleport-tls-ca"
readOnly: true
{{- end }}
{{- if contains "jamf" (.Values.roles | toString) }}
- mountPath: /etc/teleport-jamf-api-credentials
name: "jamf-api-credentials"
readOnly: true
{{- end }}
{{- if .Values.extraVolumeMounts }}
{{- toYaml .Values.extraVolumeMounts | nindent 8 }}
{{- end }}
Expand Down Expand Up @@ -207,6 +212,11 @@ spec:
name: "teleport-tls-ca"
readOnly: true
{{- end }}
{{- if contains "jamf" (.Values.roles | toString) }}
- mountPath: /etc/teleport-jamf-api-credentials
name: "jamf-api-credentials"
readOnly: true
{{- end }}
{{- if .Values.extraVolumeMounts }}
{{- toYaml .Values.extraVolumeMounts | nindent 8 }}
{{- end }}
Expand All @@ -229,6 +239,11 @@ spec:
secret:
secretName: {{ .Values.tls.existingCASecretName }}
{{- end }}
{{- if contains "jamf" (.Values.roles | toString) }}
- name: "jamf-api-credentials"
secret:
secretName: {{ .Values.jamfCredentialsSecret.name }}
{{- end }}
{{- if .Values.extraVolumes }}
{{- toYaml .Values.extraVolumes | nindent 6 }}
{{- end }}
Expand Down
Loading

0 comments on commit dfc0901

Please sign in to comment.