# Use ziti PKI as intermediate / subordanary ca

**URL:** https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588
**Category:** Uncategorized
**Created:** [September 1, 2023, 7:29pm UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588 "2023-09-01T19:29:29Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![Metz](https://avatars.discourse-cdn.com/v4/letter/m/c77e96/32.png) [@Metz](https://openziti.discourse.group/u/Metz)
#### Post date: [September 1, 2023, 7:29pm UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/1 "2023-09-01T19:29:29Z")

</div>

I've a private CA running and like to setup the openziti pki as intermediate / subordanary ca from my private pki. Also I like to stay with the quickstart docker-compose setup for now.

Is this setup possible?

---

<div class="post-metadata">

### Author: ![TheLumberjack](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/thelumberjack/32/113_2.png) [@TheLumberjack](https://openziti.discourse.group/u/TheLumberjack)
#### Post date: [September 1, 2023, 7:43pm UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/2 "2023-09-01T19:43:05Z")

</div>

Probably not, with the quickstart... The quickstart is _ **very** _ opinionated. It's evolved tremendously since it's original inception but it's still not flexible enough to handle this particular request. Once you start to explore outside of the quickstart for PKI, I'd say you are probably at the point where you kinda need to learn how all the config files pieces come together.

I think you can do what you want, but I wouldn't use the quickstart at this point. Instead, I would say you probably should look at the bare-bones containers that just have the ziti cli in them.

I actually think this would be a fun and interesting Ziti TV to do and it's docs that we need to have. Our Ziti TV schedule is packed for the next few weeks but since this sounds like fun I might just make a one-off video illustrating how to do this. Assuming I'm successful, I'll post it back along with the commands and then I'll put an issue in to get it properly turned into doc/a guide.

But for now, I'd say the answer is "probably not"...

---

<div class="post-metadata">

### Author: ![Metz](https://avatars.discourse-cdn.com/v4/letter/m/c77e96/32.png) [@Metz](https://openziti.discourse.group/u/Metz)
#### Post date: [September 1, 2023, 7:53pm UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/3 "2023-09-01T19:53:24Z")

</div>

ok Thank you.

A session on Ziti TV or a illustrating video would be cool.  
Take your time. I still have a lot of other stuff in the pipeline.

btw I'm looking to move to step-ca in future. The have a cool raspherry setup and also a docker-compose setup.

> **[Build a Tiny Certificate Authority For Your Homelab](https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/)**
>
> Let's make a tiny, standalone CA! We'll use a Raspberry Pi 4, YubiKey 5 NFC, and Infinite Noise TRNG.

---

<div class="post-metadata">

### Author: ![Metz](https://avatars.discourse-cdn.com/v4/letter/m/c77e96/32.png) [@Metz](https://openziti.discourse.group/u/Metz)
#### Post date: [September 3, 2023, 6:41am UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/4 "2023-09-03T06:41:58Z")

</div>

In case you @TheLumberjack like to do the illustrating video based on the external step-ca ore someone like to try step-ca here is how I got the step-ca up and running.

Create a compose `vi dockerfile-compose.yml`:

```auto

version: '3.9'

services:
  ca:
    image: smallstep/step-ca:latest
    container_name: step-ca
    hostname: step-ca
    volumes:
      - ./step-ca:/home/step
    environment:
      # Cert Authority (i.e., PrivateCorp CA). Shown on all issued certs.
      - "DOCKER_STEPCA_INIT_NAME=Ziti CA
      # Comma-separated list of hostnames/IP addresses on which the CA accept requests
      - "DOCKER_STEPCA_INIT_DNS_NAMES=ca.ziti
      # Provisioner.
      - "DOCKER_STEPCA_INIT_PROVISIONER_NAME=admin
      # Password for encrypted CA Keys & Provisioner
      - "DOCKER_STEPCA_INIT_PASSWORD=changeMe$$32782265
    restart: unless-stopped
    networks:
      ca:
        aliases:
          - ca.ziti

  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "127.0.0.1:80:80"
      - "127.0.0.1:443:443"
    volumes:
      - ./caddy/data/:/data/
      - ./caddy/config/:/config/
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile
    networks:
      ca:
        aliases:
          - acme.ziti

networks:
  ca:

```

Create a Caddy File `mkdir caddy; vi caddy/Caddyfile`

```auto
https://acme.ziti {
  # Inbound TLS connection configuration
  tls {
    # Configure Caddy's internal ACME client
    # to get a server certificate from `step-ca`
    issuer acme {
      dir https://ca.ziti:9000/acme/acme/directory
      email my@example.com
      trusted_roots /config/root_ca.crt
      disable_tlsalpn_challenge
    }
  }
  # Backend TLS connection to step-ca
  reverse_proxy /acme/acme/* https://ca.ziti:9000 {
    transport http {
      # This allows the proxy to complete a trust
      # chain by trusting step-ca's root.
      tls_trusted_ca_certs /config/root_ca.crt
    }
  }
}

```

Strat docker containers `docker compose up`  
Verify the Certs and activate ACME inside the container `docker exec -ti step-ca bash`:

```auto
step ca provisioner list
step ca provisioner add acme --type ACME
step ca provisioner update acme --x509-min-dur=20m --x509-max-dur=2160h --x509-default-dur=2160h # 90 days lifetime of certs, default 24h

step certificate verify certs/intermediate_ca.crt --roots certs/root_ca.crt # empty result means ok
step certificate inspect certs/intermediate_ca.crt --roots certs/root_ca.crt

```

Create and verify the intermediate cert for openziti inside the container `docker exec -ti step-ca bash`:

```auto
step certificate create --profile intermediate-ca --ca ~/certs/root_ca.crt --ca-key ~/secrets/root_ca_key "Ziti Corporation" ziti_ca.crt ziti_ca_key
mv ziti_ca.crt ~/certs/
mv ziti_ca_key ~/secrets/
step certificate inspect certs/ziti_ca.crt --roots certs/root_ca.crt

```

Copy the newly created root ca cert to caddy and restart caddy. (During `docker compose up` the cert will be created.)

```auto
cp step-ca/certs/root_ca.crt caddy/config/root_ca.crt
docker restart caddy

```

For production use this might be interesting:

- [Production considerations when running a certificate authority server](https://smallstep.com/docs/step-ca/certificate-authority-server-production/)
- create an offline root ca and only run an online intermediate ca
  - [Build a Tiny Certificate Authority For Your Homelab](https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/)
  - [Create a new Certificate Authority or an intermediate CA from your existing PKI.](https://smallstep.com/docs/tutorials/intermediate-ca-new-ca/#requirements)

---

<div class="post-metadata">

### Author: ![Metz](https://avatars.discourse-cdn.com/v4/letter/m/c77e96/32.png) [@Metz](https://openziti.discourse.group/u/Metz)
#### Post date: [September 3, 2023, 6:57am UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/5 "2023-09-03T06:57:34Z")

</div>

If you like to use a private CA on your ziti console ZAC then extend your quickstart  
Add Caddy to your OpenZiti Quickstart compose file `vi dockerfile-compose.yml`:

```auto
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "127.0.0.1:80:80"
      #- "127.0.0.1:443:443" # zac only accessible via ziti network
      - "443:443"
    volumes:
      - ./caddy/data/:/data/
      - ./caddy/config/:/config/
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile
    networks:
      - ziti

```

Create a Caddy File `mkdir caddy; vi caddy/Caddyfile`. Important: change **ctrl.ziti** to the name of your controller.

```auto
{
  email my@example.com
  acme_ca https://acme.ziti/acme/acme/directory
  acme_ca_root /config/root_ca.crt
}

ctrl.ziti {
  reverse_proxy https://ziti-console:8443 {
    transport http {
      tls
      tls_insecure_skip_verify
    }
  }
}

```

Copy / Paste the root ca from step-ca to this server `vi caddy/config/root_ca.crt`

Openziti Rules. Important: Adapt \ ***.ziti** to your ziti identities and the Role **AcmeServers** to your ca and **AcmeClients** to your clients. Those Rules will only work for certificates whith the same name as your identity.

```auto
ziti edge create config AcmeClientSvc.host.v1 host.v1 '{"protocol":"tcp","address":"acme.ziti", "port":443}\'
ziti edge create config AcmeClientSvc.intercept.v1 intercept.v1 '{"protocols":["tcp"],"addresses":["acme.ziti"], "portRanges":[{"low":443, "high":443}]}'
ziti edge create service AcmeClientSvc --configs AcmeClientSvc.intercept.v1,AcmeClientSvc.host.v1
ziti edge create service-policy AcmeClientSvc.policy.bind Bind --service-roles "@AcmeClientSvc" --identity-roles "#AcmeServers"
ziti edge create service-policy AcmeClientSvc.policy.dial Dial --service-roles "@AcmeClientSvc" --identity-roles "#AcmeClients"

ziti edge create config AcmeServerHttpSvc.host.v1 host.v1 '{"protocol":"tcp","address":"127.0.0.1", "port":80, "listenOptions":{"bindUsingEdgeIdentity":true} }'
ziti edge create config AcmeServerHttpSvc.intercept.v1 intercept.v1 '{"protocols":["tcp"],"addresses":["*.ziti"], "portRanges":[{"low":80, "high":80}], "dialOptions":{"identity":"$dst_hostname"}}'
ziti edge create service AcmeServerHttpSvc --configs AcmeServerHttpSvc.intercept.v1,AcmeServerHttpSvc.host.v1
ziti edge create service-policy AcmeServerHttpSvc.policy.bind Bind --service-roles "@AcmeServerHttpSvc" --identity-roles "#AcmeClients"
ziti edge create service-policy AcmeServerHttpSvc.policy.dial Dial --service-roles "@AcmeServerHttpSvc" --identity-roles "#AcmeServers"

ziti edge create config AcmeServerAlpnSvc.host.v1 host.v1 '{"protocol":"tcp","address":"127.0.0.1", "port":443, "listenOptions":{"bindUsingEdgeIdentity":true} }'
ziti edge create config AcmeServerAlpnSvc.intercept.v1 intercept.v1 '{"protocols":["tcp"],"addresses":["*.ziti"], "portRanges":[{"low":443, "high":443}], "dialOptions":{"identity":"$dst_hostname"}}'
ziti edge create service AcmeServerAlpnSvc --configs AcmeServerAlpnSvc.intercept.v1,AcmeServerAlpnSvc.host.v1
ziti edge create service-policy AcmeServerAlpnSvc.policy.bind Bind --service-roles "@AcmeServerAlpnSvc" --identity-roles "#AcmeClients"
ziti edge create service-policy AcmeServerAlpnSvc.policy.dial Dial --service-roles "@AcmeServerAlpnSvc" --identity-roles "#AcmeServers"

```

Add an DNS entry on your CA Server for **acme.ziti** in your main dns or on the localhost in case you use the linux tunneler and not the docker tunneler. `vi /etc/hosts`

```auto
127.0.0.1 localhost acme.ziti

```

Add your public certificate to your Client mashine. In case of Fedora:

```auto
sudo vim /etc/pki/ca-trust/source/anchors/root_ca.ziti.pem # copy / paste the cert
sudo update-ca-trust
# restart your browser

```

---

<div class="post-metadata">

### Author: ![TheLumberjack](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/thelumberjack/32/113_2.png) [@TheLumberjack](https://openziti.discourse.group/u/TheLumberjack)
#### Post date: [September 6, 2023, 11:58am UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/6 "2023-09-06T11:58:20Z")

</div>

Hi @Metz, just checking in. I saw you made a bunch of progress on this thread. Do you still need to figure out how to use an independently provisioned CA with your network? I'm happy to produce a super quick video showing you how if you would like it and still need it.

Cheers

---

<div class="post-metadata">

### Author: ![Metz](https://avatars.discourse-cdn.com/v4/letter/m/c77e96/32.png) [@Metz](https://openziti.discourse.group/u/Metz)
#### Post date: [September 6, 2023, 8:13pm UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/7 "2023-09-06T20:13:43Z")

</div>

@TheLumberjack, I saw your Video from the other post [What does the quickstart do that I need to do myself? - #4 by TheLumberjack](https://openziti.discourse.group/t/what-does-the-quickstart-do-that-i-need-to-do-myself/1600/4)  
Looks like here you have already answered a lot of my questions.

I was busy until know with other stuff but will for sure test the setup this week or next week.

---

<div class="post-metadata">

### Author: ![TheLumberjack](https://yyz2.discourse-cdn.com/free1/user_avatar/openziti.discourse.group/thelumberjack/32/113_2.png) [@TheLumberjack](https://openziti.discourse.group/u/TheLumberjack)
#### Post date: [September 6, 2023, 8:37pm UTC](https://openziti.discourse.group/t/use-ziti-pki-as-intermediate-subordanary-ca/1588/8 "2023-09-06T20:37:51Z")

</div>

Ok cool. I thought it would cover much/most of what you needed. The one bit of "magic" you will want is in the script I was using to make sure the instructions work here [https://github.com/dovholuknf/openziti-compose/blob/main/compose-from-custom-pki.sh](https://github.com/dovholuknf/openziti-compose/blob/main/compose-from-custom-pki.sh)

The most important lines, to "import" your key/cert to the ZITI\_PKI location, would be these:

```auto
export ZITI_HOME="/opt/ziti/quickstart"
export ZITI_PKI="${ZITI_HOME}/pki"

EXTERNAL_CA_INTERMEDIATE_NAME="intermediate.from.external.ca"
mkdir -p $ZITI_PKI/$EXTERNAL_CA_INTERMEDIATE_NAME/keys
mkdir -p $ZITI_PKI/$EXTERNAL_CA_INTERMEDIATE_NAME/certs
touch $ZITI_PKI/$EXTERNAL_CA_INTERMEDIATE_NAME/index.txt

cp /tmp/external.key $ZITI_PKI/$EXTERNAL_CA_INTERMEDIATE_NAME/keys/$EXTERNAL_CA_INTERMEDIATE_NAME.key
cp /tmp/external.cert $ZITI_PKI/$EXTERNAL_CA_INTERMEDIATE_NAME/certs/$EXTERNAL_CA_INTERMEDIATE_NAME.cert

```

Then, when you run your ziti pki commands, you supply THAT as the `--ca-name`, as shown in that video. For example, generating an intermediate for the network-components/control plane would be something like:

```auto
ZITI_CTRL_CA_NAME="${ZITI_HOSTNAME}-network-components"
ziti pki create intermediate \
  --pki-root="${ZITI_PKI}" \
  --ca-name "${EXTERNAL_CA_INTERMEDIATE_NAME}" \
  --intermediate-name "${ZITI_CTRL_CA_NAME}" \
  --intermediate-file "${ZITI_CTRL_CA_NAME}" \
  --max-path-len "1"

```

I think that'll probably give you all you need, but if you want to refer to that script for a 'full example', it's there. Let me know if you need more help! 🙂
