# Management API authentication

**URL:** <https://openziti.discourse.group/t/management-api-authentication/1480>\
**Category:** Support\
**Created:** [August 11, 2023, 12:25pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480 "2023-08-11T12:25:51Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 12:25pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/1 "2023-08-11T12:25:51Z")

</div>

Hey, I’m working on some ansible modules to automate resource (identity, service, etc) creation through the REST API, and I’ve a question about the authentication part.

On the docs ([Edge Management API Reference | OpenZiti](https://openziti.io/docs/reference/developer/api/edge-management-reference#tag/Authentication/operation/authenticate)) it says that we can auth either using user/pw, certificate or external jwt.

How the certificate or external jwt can be supplied to the API ?

What kind of certificate are we talking about in here ? A client cert made using the self signed CA ?

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [August 11, 2023, 12:27pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/2 "2023-08-11T12:27:21Z")

</div>

Hey @arslane ! That’s awesome. Do you want to authenticate with the ziti CLI or the Ansible uri module or something else? I’ll send some examples.

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 12:30pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/3 "2023-08-11T12:30:39Z")

</div>

I’ll be authenticating through some Python code (probably requests lib). The idea is to grab the ztSession token so it can be used to do some other stuff (creating Identities, Services, etc).

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [August 11, 2023, 12:33pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/4 "2023-08-11T12:33:10Z")

</div>

Very cool. Since you’re authenticating with the Ziti mgmt API in Python, would you like to use the Python client library generated from the spec?

Here’s [the authentication piece](https://github.com/openziti-test-kitchen/openziti-edge-management-python/blob/main/openziti_edge_management/api/authentication_api.py).

I’ll add more context here.

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 12:37pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/5 "2023-08-11T12:37:54Z")

</div>

Oh didn’t knew such thing existed, this is gonna save me alot of time !

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [August 11, 2023, 12:41pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/6 "2023-08-11T12:41:19Z")

</div>

Glad to hear that! I’m really interested to see how you approach this with Ansible and I look forward to getting more familiar with the Py client myself. Are you thinking a separate task module for each type of Ziti resource, e.g., service, or separate module for each use case, e.g., simple-tunnel-service?

Here’s a generic cURL example for using a client authentication certificate to obtain a session token. You’ll see the Py client too has this `cert` method param.

```bash
curl \
    --request POST \
    --header 'content-type: application/json' \
    --data '{}' \
    --silent --show-error --fail \
    --cert zitiadmin-client.crt \
    --key zitiadmin-client.key \
    --cacert ziti-ca-bundle.pem \
    "https://mgmt.ziti.example.com/edge/management/v1/authenticate?method=cert"

```

The value of `.data.token` in the response must be included in subsequent requests as HTTP header `zt-session` ([link to doc](https://openziti.io/docs/learn/core-concepts/security/authentication/auth/#api-sessions)). I’ll page in someone that’s used the Py client more than me to offer a little more help.

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 12:46pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/7 "2023-08-11T12:46:05Z")

</div>

> [@qrkourier](#):
>
> Are you thinking a separate task module for each type of Ziti resource, e.g., service, or separate module for each use case, e.g., simple-tunnel-service?

Yeah I think 1 module for each resource type is a good idea, each module have to be idempotent. This would give much more flexibility

---

<div class="post-metadata">

**Author:** ![sabedevops](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/sabedevops/32/552_2.png) [@sabedevops](https://openziti.discourse.group/u/sabedevops)\
**Post date:** [August 11, 2023, 12:49pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/8 "2023-08-11T12:49:09Z")

</div>

Hey Arslane,

We look forward to some help in this space. Please use the below code as a pseudo-example of how to use one of the generated Python API clients with `cert` based authentication:

> <https://github.com/openziti-test-kitchen/ansible-collection/blob/main/community.openziti/plugins/inventory/connection_autodiscovery.py#L73>

Note, at the time we wrote the above, there existed `python-prior` OpenAPI generator. Let me bump the `management` api code to be the code generated by the new generator. They should be close enough that the original code should still work.

Edit: As a pseudo guide for these generated clients…please see: [OpenAPI Python Clients](https://blog.openziti.io/openapi-python-clients)

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [August 11, 2023, 12:52pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/9 "2023-08-11T12:52:27Z")

</div>

I wonder if generating the modules from the client lib for some of the Ziti resource types is possible. 🤔

For the service module in particular it might be easier to have separate modules because services can take so many different forms. That way each module can have a simpler set of module args and there’s not so much branching logic in each service module, e.g., `ziti_service_point_to_point_tunnel` and `ziti_service_subnet_tunnel`, `ziti_service_embedded`, etc. Just a thought!

EDIT: I kept thinking and realized another way to avoid a spaghetti service module is to separate the Ziti configs from Ziti services cleanly (service module doesn’t manage Ziti configs). That way, there’s no abstraction like “point to point tunnel” at all, and every Ansible playbook has separate tasks to manage the Ziti configs and Ziti services. Am I expressing this clearly?

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 12:59pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/10 "2023-08-11T12:59:52Z")

</div>

> [@qrkourier](#):
>
> EDIT: I kept thinking and realized another way to avoid a spaghetti service module is to separate the Ziti configs from Ziti services cleanly (service module doesn’t manage Ziti configs). That way, there’s no abstraction like “point to point tunnel” at all, and every Ansible playbook has separate tasks to manage the Ziti configs and Ziti services. Am I expressing this clearly?

So we should have a module that manages configs and another to manage services ? That sounds great !

---

<div class="post-metadata">

**Author:** ![sabedevops](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/sabedevops/32/552_2.png) [@sabedevops](https://openziti.discourse.group/u/sabedevops)\
**Post date:** [August 11, 2023, 1:02pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/11 "2023-08-11T13:02:18Z")

</div>

Okay, I’ve bumped the code to use the `python` generator from the latest docker image. I’ll give it a test in a bit to make sure it will work for you and report back. Let me know if you have any issues.

I’ll say that you’ll need to give some thought as to how to create identities idempotently. Enrolling an identity consumes its JWT, so you might need to see if matching authenticator exists for the identity to determine if you should attempt to enroll, or maybe use the JWT enrollment files as markers of a certain sort.

---

<div class="post-metadata">

**Author:** ![sabedevops](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/sabedevops/32/552_2.png) [@sabedevops](https://openziti.discourse.group/u/sabedevops)\
**Post date:** [August 11, 2023, 1:04pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/12 "2023-08-11T13:04:30Z")

</div>

I think 1 module per API resrouce unless it makes more sense to coalesce the functionality. `configs` are independent from `services` (for example, for service config overrides)

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 1:13pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/13 "2023-08-11T13:13:05Z")

</div>

> [@sabedevops](#):
>
> Okay, I’ve bumped the code to use the `python` generator from the latest docker image. I’ll give it a test in a bit to make sure it will work for you and report back. Let me know if you have any issues.

Alright thanks !

> [@sabedevops](#):
>
> so you might need to see if matching authenticator exists for the identity

Yeah, I'll have to do that for every resource actually.

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 2:42pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/14 "2023-08-11T14:42:04Z")

</div>

Just thought about something, I’m using Hashicorp Vault to store my homelab secrets and to generate short-lived credentials to some APIs/Apps trough Vault custom engines. Has anyone worked on a Openziti Engine for Vault ? That could be huge

---

<div class="post-metadata">

**Author:** ![PhilipGriffiths](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/philipgriffiths/32/341_2.png) [@PhilipGriffiths](https://openziti.discourse.group/u/PhilipGriffiths)\
**Post date:** [August 11, 2023, 2:47pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/15 "2023-08-11T14:47:29Z")

</div>

I know @TheLumberjack has done some work around Vault… not sure if it extends to an engine…

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 5:39pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/16 "2023-08-11T17:39:16Z")

</div>

> [@sabedevops](#):
>
> how to use one of the generated Python API clients with `cert` based authentication

The `identity_file` is it a non-enrolled JWT file ?

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [August 11, 2023, 6:07pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/17 "2023-08-11T18:07:57Z")

</div>

It's a JSON identity config file for an enrolled Ziti identity with admin permission. The easiest way to obtain this file is to

1. create an admin identity to obtain an enrollment JWT
2. enroll with the token to obtain the JSON identity config file

Here's a `ziti` CLI examples to illustrate, in case you want to orchestrate this part of the process outside the Python module.

### create admin identity

```bash
ziti edge create identity device admin-with-cert-auth \
  --jwt-output-file /tmp/admin-with-cert-auth.jwt \
  --admin

```

### enroll admin identity

```bash
$ ziti edge enroll --jwt /tmp/admin-with-cert-auth.jwt 
INFO generating 4096 bit RSA key                  
INFO enrolled successfully. identity file written to: /tmp/admin-with-cert-auth.json 

```

### authenticate with JSON identity config (cert authentication)

```bash
$ jq -r '.id.key' < /tmp/admin-with-cert-auth.json \
  | sed 's/^pem://' > /tmp/admin-with-cert-auth.key
$ jq -r '.id.cert' < /tmp/admin-with-cert-auth.json \
  | sed 's/^pem://' > /tmp/admin-with-cert-auth.cert
$ jq -r '.id.ca' < /tmp/admin-with-cert-auth.json \
  | sed 's/^pem://' > /tmp/admin-with-cert-auth.cacert

$ ziti edge login mgmt.ziti.example.com:443 \
    --username admin-with-cert-auth \
    --client-cert /tmp/admin-with-cert-auth.cert \
    --client-key /tmp/admin-with-cert-auth.key \
    --ca /tmp/admin-with-cert-auth.cacert 

Token: d34a3a91-f0ea-4f8f-a055-cbd8b45fb4b8
Saving identity 'default' to /home/kbingham/.config/ziti/ziti-cli.json

```

I was surprised not to find a way to use the enrolled JSON identity config file directly ([enhancement request](https://github.com/openziti/ziti/issues/127)), so I parsed out the cert and key to verify it worked.

EDIT: added cacert to CLI cert auth example

---

<div class="post-metadata">

**Author:** ![sabedevops](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/sabedevops/32/552_2.png) [@sabedevops](https://openziti.discourse.group/u/sabedevops)\
**Post date:** [August 11, 2023, 7:03pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/18 "2023-08-11T19:03:16Z")

</div>

Correct, the link to the collection code from above just shows an example of unpacking the `identity.json` file into three (ca, cert, key) separate `tempfile` managed temporary files (the way it’s written, these get automatically cleaned up on program termination).

---

<div class="post-metadata">

**Author:** ![arslane](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/arslane/32/408_2.png) [@arslane](https://openziti.discourse.group/u/arslane)\
**Post date:** [August 11, 2023, 8:09pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/19 "2023-08-11T20:09:27Z")

</div>

Thanks to both of you !

On the identity creation schema [Edge Management API Reference | OpenZiti](https://openziti.io/docs/reference/developer/api/edge-management-reference#tag/Identity/operation/createIdentity) the `enrollment` type basically describe how that identity will be authenticating to Ziti right ? and  
`ott` → Generates the enrollment with the JWT → Once the JWT is enrolled we can use the identity  
`updb` → same as ott + username/pw authentication, right ?  
`ottca` → What does that do ?

---

<div class="post-metadata">

**Author:** ![qrkourier](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/qrkourier/32/52_2.png) [@qrkourier](https://openziti.discourse.group/u/qrkourier)\
**Post date:** [August 11, 2023, 8:26pm UTC](https://openziti.discourse.group/t/management-api-authentication/1480/20 "2023-08-11T20:26:35Z")

</div>

You’re welcome!

You would use `ottca` instead of `ott` if you plan to supply the client authentication certificate from a [3rd party CA](https://openziti.io/docs/learn/core-concepts/security/enrollment/#ott-ca-enrollment) that you’ve verified with Ziti.

That’s right, `ott` enrollment means Ziti’s edge CA will issue the client auth certificate when you enroll with the token.

Also correct, `updb` is “the username/password database authentication mechanism”

[Next page](https://openziti.discourse.group/t/management-api-authentication/1480.md?page=2)
