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

Add support for Certificate and SNIs #102

Merged
merged 1 commit into from
Feb 4, 2018
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
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ consumers:
upstreams:
- name: "mockbinUpstream"
ensure: "present"
targets:
targets:
- target: "server1.mockbin:3001"
attributes:
weight: 50
Expand All @@ -347,6 +347,36 @@ upstreams:
slots: 100
```

### Certificates & SNIs

*A certificate object represents a public certificate/private key pair for an SSL certificate. These objects are used by Kong to handle SSL/TLS termination for encrypted requests. Certificates are optionally associated with SNI objects to tie a cert/key pair to one or more hostnames.*

[Kong Certificate Object Reference](https://getkong.org/docs/0.11.x/admin-api/#certificate-object)

*An SNI object represents a many-to-one mapping of hostnames to a certificate. That is, a certificate object can have many hostnames associated with it; when Kong receives an SSL request, it uses the SNI field in the Client Hello to lookup the certificate object based on the SNI associated with the certificate.*

[Kong SNI Objects Reference](https://getkong.org/docs/0.11.x/admin-api/#sni-objects)

```yaml
certificates:
- ensure: present
cert: >-
-----BEGIN CERTIFICATE-----
MIIDMjCCAhqgAwIBAgIJAPgRdnOdnX/SMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV
....
key: >-
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAo5BpOQY2AV/1L2QEdSip75rHh3Khs2knNtMLIrP26MHyidtX
....
snis:
- name: example.com
ensure: present
- name: www.example.com
ensure: present
```

> Notice that SNIs are an list of object e.g. `{ name: example.com, ensure: present }` different Kong api itself where it is a list of hostnames


## Migrating from Kong <=0.9 to >=0.10

Expand Down
129 changes: 129 additions & 0 deletions examples/certificates.example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
certificates example
--------------------

## Config file

```yaml
certificates:
- ensure: present
cert: '-----BEGIN CERTIFICATE-----
MIIDMjCCAhqgAwIBAgIJAPgRdnOdnX/SMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV
BAMTD3d3dy5leGFtcGxlLmNvbTAeFw0xNzExMTkxODUxMDlaFw0yNzExMTcxODUx
MDlaMBoxGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAKOQaTkGNgFf9S9kBHUoqe+ax4dyobNpJzbTCyKz9ujB
8onbV3e8HO5TEQVpIwob3bQ59ZmNkhZxI6jp4ykmXN8gtPOXvWGiSILBcY4p6ttC
RyyVJHSGCKDS5+oUsQA2+ql0ce+ZYl7ePD2kFgzodKCspQaKUe4jvdcEDwsHLmAH
gnFf9oFCCk2McKVH4Vt/YSD6NriTpV0KBCOG260E3vtYWto+djK1AswJCbiTFfnA
a1Vojmu9uX66jfQ/ivZrBFZKHqGtxpBaBa9HV+LaEqehjy2LwQX4fVT4uawDnEM5
zyy+rR+b0h9lTntI7J7pbAm3zywBzaMtQp0boW20C0UCAwEAAaN7MHkwHQYDVR0O
BBYEFJ8KvTYTyM64g0ISOl/HmbM9Y7o/MEoGA1UdIwRDMEGAFJ8KvTYTyM64g0IS
Ol/HmbM9Y7o/oR6kHDAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb22CCQD4EXZz
nZ1/0jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCO9jaWppfOI4Qn
R5/NHp1TYxsWei7Xjr0X7wLVgRZGqzhzPKG4eZR7zfXQfg+ufBx1M3/H5DCTv0cm
CgIjatSRxypV9xOzbakAgcSKw/iqjeDZYN/09iVTICONW507X35ONmw6No3tbVLV
tnuGhtcVOyYBtRUpFc9lCWPYpFVMRMMKXnbdXahlt3IPMPx2QY7nWjAo/oC9oZ2A
RMdp9Sav8eCYf8bLR/A+p5DodwvYgOn5sEUXQeYB/w+VsjmYU01NfMR9NxwsDA5b
gXYz44Dl4jhoi/tz/zIOOGA4DlmuJBpMeYtp9SvJ8qhpx3ul/3C2KFOI+/BzdVSl
L5mKwXjd
-----END CERTIFICATE-----'

key: '-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAo5BpOQY2AV/1L2QEdSip75rHh3Khs2knNtMLIrP26MHyidtX
d7wc7lMRBWkjChvdtDn1mY2SFnEjqOnjKSZc3yC085e9YaJIgsFxjinq20JHLJUk
dIYIoNLn6hSxADb6qXRx75liXt48PaQWDOh0oKylBopR7iO91wQPCwcuYAeCcV/2
gUIKTYxwpUfhW39hIPo2uJOlXQoEI4bbrQTe+1ha2j52MrUCzAkJuJMV+cBrVWiO
a725frqN9D+K9msEVkoeoa3GkFoFr0dX4toSp6GPLYvBBfh9VPi5rAOcQznPLL6t
H5vSH2VOe0jsnulsCbfPLAHNoy1CnRuhbbQLRQIDAQABAoIBAAjbgCc7Y99NL/zi
AK/LhPBZxGZcWc9aaWo5oYe+kSdnoVe/zgvI3xQ04V4WpHQesDHbVaZ8GSYn+FNk
Xw3SawMWRVZPqEzKOf0CtsCJGpPHEg2jAfdhbsQux6pQdolZcNeOW8Eq4D3c8Qwx
f5QxXmd5EfK5uNgZjWVAbgQd3nAKwd/a6AHjppTp6ikNJFU4WU3oi/2N7czpOKFi
4tq0Img8VqcKekL4LYUYk8RXi6uk+c5ookB1Q2wh/Fpf9oeLN4kBsxXMt8bEg95D
2Ks5Ekw4yOWnQ8OwfXMWDk46NKMcR7ZYoqfhCk6sc5v6ZFQerJQUBGi2o1Jq2u7Y
5TIl+4ECgYEA1ybYXpGQIIElHbV90RKc6McoF+yeost1ZWyv/646vwWr+pmkgA32
iZnAOvaoAaRJbD5d6gIFdG49lmv36wPvBbzmWBkS9sWujTaEIFHSd9H1R8UxGuud
WqnxrY0cYf6fl4Jrguro6PwAv4gsdCt1HA6d9E85+bHP1lr+R823G2ECgYEAwp44
QdMCvYpLQkbCiLh/UlF2zqZPOQpm2T4NKHxfuH6HKdYyI+ptyx6oP94r/4u7/sYT
nHjCKR7QLGE7qFmnH9Yb2jCd3zFwNBsCoHFhzj6MYzgoV42tpUJl8jRcq351g7hw
Fw2yZG8mW/4lwOhhuVAaUyCngoAs7Jq004bM/mUCgYA/y/PyrsUG7mR8F7n0Ccnf
OFbKKU6sxRnNdloFvbsLs3nYeECP/BPzn1Sh50vQGM/wudmNLwZBDQNUHDXKSUNR
9z5yNxUpeVqV4ulwz/JRtz89BdrWubDSFnxkUuhsolzeRzzr+A4SL89k+9L6q3wx
UqBBtlBhmvke/aJS1kwKYQKBgQCyn7N0vu5Z9u9CQl3UTLoXXMvVuZEnAmQJakl7
akQUupTmEkFs84KYFmhITmtFngQLP9PKHo/eW/incwrlZnvc3ZAsv8h2jRK10ECl
78rcGE6T1nw4d8Hz1zBokCSqBmRnZEYE8r5ULiwf7PDL0L2470tqFqOIRIp3Ezt6
ldPafQKBgQCS2FyQjk6ccJDYQSaERZeVZ7aw/WYU6CMt64WqIcA2sZsHACPg1JuH
rvANyaCjA5QV2cxhZgw9YmwUkP5I6XftplGB81CjmTguGjJ/k5SS8sA2DCHZUna6
vxTZvHMdrkoTodEYmy67Kno3NZotwhRUIdgdQhDN+aG+wjOCxKMTRQ==
-----END RSA PRIVATE KEY-----'
snis:
- ensure: present
name: example.com
- ensure: present
name: www.example.com

```

## Using curl

For illustrative purpose a cURL calls would be the following

### create certificate

```sh
$ curl -i -X POST -H "Content-Type: application/json" \
--url http://localhost:8001/certificates \
--data '{"key":"-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAo5BpOQY2AV/1L2QEdSip75rHh3Khs2knNtMLIrP26MHyidtX d7wc7lMRBWkjChvdtDn1mY2SFnEjqOnjKSZc3yC085e9YaJIgsFxjinq20JHLJUk dIYIoNLn6hSxADb6qXRx75liXt48PaQWDOh0oKylBopR7iO91wQPCwcuYAeCcV/2 gUIKTYxwpUfhW39hIPo2uJOlXQoEI4bbrQTe+1ha2j52MrUCzAkJuJMV+cBrVWiO a725frqN9D+K9msEVkoeoa3GkFoFr0dX4toSp6GPLYvBBfh9VPi5rAOcQznPLL6t H5vSH2VOe0jsnulsCbfPLAHNoy1CnRuhbbQLRQIDAQABAoIBAAjbgCc7Y99NL/zi AK/LhPBZxGZcWc9aaWo5oYe+kSdnoVe/zgvI3xQ04V4WpHQesDHbVaZ8GSYn+FNk Xw3SawMWRVZPqEzKOf0CtsCJGpPHEg2jAfdhbsQux6pQdolZcNeOW8Eq4D3c8Qwx f5QxXmd5EfK5uNgZjWVAbgQd3nAKwd/a6AHjppTp6ikNJFU4WU3oi/2N7czpOKFi 4tq0Img8VqcKekL4LYUYk8RXi6uk+c5ookB1Q2wh/Fpf9oeLN4kBsxXMt8bEg95D 2Ks5Ekw4yOWnQ8OwfXMWDk46NKMcR7ZYoqfhCk6sc5v6ZFQerJQUBGi2o1Jq2u7Y 5TIl+4ECgYEA1ybYXpGQIIElHbV90RKc6McoF+yeost1ZWyv/646vwWr+pmkgA32 iZnAOvaoAaRJbD5d6gIFdG49lmv36wPvBbzmWBkS9sWujTaEIFHSd9H1R8UxGuud WqnxrY0cYf6fl4Jrguro6PwAv4gsdCt1HA6d9E85+bHP1lr+R823G2ECgYEAwp44 QdMCvYpLQkbCiLh/UlF2zqZPOQpm2T4NKHxfuH6HKdYyI+ptyx6oP94r/4u7/sYT nHjCKR7QLGE7qFmnH9Yb2jCd3zFwNBsCoHFhzj6MYzgoV42tpUJl8jRcq351g7hw Fw2yZG8mW/4lwOhhuVAaUyCngoAs7Jq004bM/mUCgYA/y/PyrsUG7mR8F7n0Ccnf OFbKKU6sxRnNdloFvbsLs3nYeECP/BPzn1Sh50vQGM/wudmNLwZBDQNUHDXKSUNR 9z5yNxUpeVqV4ulwz/JRtz89BdrWubDSFnxkUuhsolzeRzzr+A4SL89k+9L6q3wx UqBBtlBhmvke/aJS1kwKYQKBgQCyn7N0vu5Z9u9CQl3UTLoXXMvVuZEnAmQJakl7 akQUupTmEkFs84KYFmhITmtFngQLP9PKHo/eW/incwrlZnvc3ZAsv8h2jRK10ECl 78rcGE6T1nw4d8Hz1zBokCSqBmRnZEYE8r5ULiwf7PDL0L2470tqFqOIRIp3Ezt6 ldPafQKBgQCS2FyQjk6ccJDYQSaERZeVZ7aw/WYU6CMt64WqIcA2sZsHACPg1JuH rvANyaCjA5QV2cxhZgw9YmwUkP5I6XftplGB81CjmTguGjJ/k5SS8sA2DCHZUna6 vxTZvHMdrkoTodEYmy67Kno3NZotwhRUIdgdQhDN+aG+wjOCxKMTRQ== -----END RSA PRIVATE KEY-----","cert":"-----BEGIN CERTIFICATE----- MIIDMjCCAhqgAwIBAgIJAPgRdnOdnX/SMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV BAMTD3d3dy5leGFtcGxlLmNvbTAeFw0xNzExMTkxODUxMDlaFw0yNzExMTcxODUx MDlaMBoxGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAKOQaTkGNgFf9S9kBHUoqe+ax4dyobNpJzbTCyKz9ujB 8onbV3e8HO5TEQVpIwob3bQ59ZmNkhZxI6jp4ykmXN8gtPOXvWGiSILBcY4p6ttC RyyVJHSGCKDS5+oUsQA2+ql0ce+ZYl7ePD2kFgzodKCspQaKUe4jvdcEDwsHLmAH gnFf9oFCCk2McKVH4Vt/YSD6NriTpV0KBCOG260E3vtYWto+djK1AswJCbiTFfnA a1Vojmu9uX66jfQ/ivZrBFZKHqGtxpBaBa9HV+LaEqehjy2LwQX4fVT4uawDnEM5 zyy+rR+b0h9lTntI7J7pbAm3zywBzaMtQp0boW20C0UCAwEAAaN7MHkwHQYDVR0O BBYEFJ8KvTYTyM64g0ISOl/HmbM9Y7o/MEoGA1UdIwRDMEGAFJ8KvTYTyM64g0IS Ol/HmbM9Y7o/oR6kHDAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb22CCQD4EXZz nZ1/0jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCO9jaWppfOI4Qn R5/NHp1TYxsWei7Xjr0X7wLVgRZGqzhzPKG4eZR7zfXQfg+ufBx1M3/H5DCTv0cm CgIjatSRxypV9xOzbakAgcSKw/iqjeDZYN/09iVTICONW507X35ONmw6No3tbVLV tnuGhtcVOyYBtRUpFc9lCWPYpFVMRMMKXnbdXahlt3IPMPx2QY7nWjAo/oC9oZ2A RMdp9Sav8eCYf8bLR/A+p5DodwvYgOn5sEUXQeYB/w+VsjmYU01NfMR9NxwsDA5b gXYz44Dl4jhoi/tz/zIOOGA4DlmuJBpMeYtp9SvJ8qhpx3ul/3C2KFOI+/BzdVSl L5mKwXjd -----END CERTIFICATE-----"}'
```

```
HTTP 201 Created
```

```
{
"created_at": "___created_at___",
"cert": "-----BEGIN CERTIFICATE----- MIIDMjCCAhqgAwIBAgIJAPgRdnOdnX/SMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV BAMTD3d3dy5leGFtcGxlLmNvbTAeFw0xNzExMTkxODUxMDlaFw0yNzExMTcxODUx MDlaMBoxGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAKOQaTkGNgFf9S9kBHUoqe+ax4dyobNpJzbTCyKz9ujB 8onbV3e8HO5TEQVpIwob3bQ59ZmNkhZxI6jp4ykmXN8gtPOXvWGiSILBcY4p6ttC RyyVJHSGCKDS5+oUsQA2+ql0ce+ZYl7ePD2kFgzodKCspQaKUe4jvdcEDwsHLmAH gnFf9oFCCk2McKVH4Vt/YSD6NriTpV0KBCOG260E3vtYWto+djK1AswJCbiTFfnA a1Vojmu9uX66jfQ/ivZrBFZKHqGtxpBaBa9HV+LaEqehjy2LwQX4fVT4uawDnEM5 zyy+rR+b0h9lTntI7J7pbAm3zywBzaMtQp0boW20C0UCAwEAAaN7MHkwHQYDVR0O BBYEFJ8KvTYTyM64g0ISOl/HmbM9Y7o/MEoGA1UdIwRDMEGAFJ8KvTYTyM64g0IS Ol/HmbM9Y7o/oR6kHDAaMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb22CCQD4EXZz nZ1/0jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCO9jaWppfOI4Qn R5/NHp1TYxsWei7Xjr0X7wLVgRZGqzhzPKG4eZR7zfXQfg+ufBx1M3/H5DCTv0cm CgIjatSRxypV9xOzbakAgcSKw/iqjeDZYN/09iVTICONW507X35ONmw6No3tbVLV tnuGhtcVOyYBtRUpFc9lCWPYpFVMRMMKXnbdXahlt3IPMPx2QY7nWjAo/oC9oZ2A RMdp9Sav8eCYf8bLR/A+p5DodwvYgOn5sEUXQeYB/w+VsjmYU01NfMR9NxwsDA5b gXYz44Dl4jhoi/tz/zIOOGA4DlmuJBpMeYtp9SvJ8qhpx3ul/3C2KFOI+/BzdVSl L5mKwXjd -----END CERTIFICATE-----",
"id": "2b47ba9b-761a-492d-9a0c-000000000001",
"key": "-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAo5BpOQY2AV/1L2QEdSip75rHh3Khs2knNtMLIrP26MHyidtX d7wc7lMRBWkjChvdtDn1mY2SFnEjqOnjKSZc3yC085e9YaJIgsFxjinq20JHLJUk dIYIoNLn6hSxADb6qXRx75liXt48PaQWDOh0oKylBopR7iO91wQPCwcuYAeCcV/2 gUIKTYxwpUfhW39hIPo2uJOlXQoEI4bbrQTe+1ha2j52MrUCzAkJuJMV+cBrVWiO a725frqN9D+K9msEVkoeoa3GkFoFr0dX4toSp6GPLYvBBfh9VPi5rAOcQznPLL6t H5vSH2VOe0jsnulsCbfPLAHNoy1CnRuhbbQLRQIDAQABAoIBAAjbgCc7Y99NL/zi AK/LhPBZxGZcWc9aaWo5oYe+kSdnoVe/zgvI3xQ04V4WpHQesDHbVaZ8GSYn+FNk Xw3SawMWRVZPqEzKOf0CtsCJGpPHEg2jAfdhbsQux6pQdolZcNeOW8Eq4D3c8Qwx f5QxXmd5EfK5uNgZjWVAbgQd3nAKwd/a6AHjppTp6ikNJFU4WU3oi/2N7czpOKFi 4tq0Img8VqcKekL4LYUYk8RXi6uk+c5ookB1Q2wh/Fpf9oeLN4kBsxXMt8bEg95D 2Ks5Ekw4yOWnQ8OwfXMWDk46NKMcR7ZYoqfhCk6sc5v6ZFQerJQUBGi2o1Jq2u7Y 5TIl+4ECgYEA1ybYXpGQIIElHbV90RKc6McoF+yeost1ZWyv/646vwWr+pmkgA32 iZnAOvaoAaRJbD5d6gIFdG49lmv36wPvBbzmWBkS9sWujTaEIFHSd9H1R8UxGuud WqnxrY0cYf6fl4Jrguro6PwAv4gsdCt1HA6d9E85+bHP1lr+R823G2ECgYEAwp44 QdMCvYpLQkbCiLh/UlF2zqZPOQpm2T4NKHxfuH6HKdYyI+ptyx6oP94r/4u7/sYT nHjCKR7QLGE7qFmnH9Yb2jCd3zFwNBsCoHFhzj6MYzgoV42tpUJl8jRcq351g7hw Fw2yZG8mW/4lwOhhuVAaUyCngoAs7Jq004bM/mUCgYA/y/PyrsUG7mR8F7n0Ccnf OFbKKU6sxRnNdloFvbsLs3nYeECP/BPzn1Sh50vQGM/wudmNLwZBDQNUHDXKSUNR 9z5yNxUpeVqV4ulwz/JRtz89BdrWubDSFnxkUuhsolzeRzzr+A4SL89k+9L6q3wx UqBBtlBhmvke/aJS1kwKYQKBgQCyn7N0vu5Z9u9CQl3UTLoXXMvVuZEnAmQJakl7 akQUupTmEkFs84KYFmhITmtFngQLP9PKHo/eW/incwrlZnvc3ZAsv8h2jRK10ECl 78rcGE6T1nw4d8Hz1zBokCSqBmRnZEYE8r5ULiwf7PDL0L2470tqFqOIRIp3Ezt6 ldPafQKBgQCS2FyQjk6ccJDYQSaERZeVZ7aw/WYU6CMt64WqIcA2sZsHACPg1JuH rvANyaCjA5QV2cxhZgw9YmwUkP5I6XftplGB81CjmTguGjJ/k5SS8sA2DCHZUna6 vxTZvHMdrkoTodEYmy67Kno3NZotwhRUIdgdQhDN+aG+wjOCxKMTRQ== -----END RSA PRIVATE KEY-----",
"snis": []
}
```

### add certificate sni

```sh
$ curl -i -X POST -H "Content-Type: application/json" \
--url http://localhost:8001/snis/ \
--data '{"name":"example.com","ssl_certificate_id":"2b47ba9b-761a-492d-9a0c-000000000001"}'
```

```
HTTP 201 Created
```

```
{
"name": "example.com",
"created_at": "___created_at___",
"ssl_certificate_id": "2b47ba9b-761a-492d-9a0c-000000000001"
}
```

### add certificate sni

```sh
$ curl -i -X POST -H "Content-Type: application/json" \
--url http://localhost:8001/snis/ \
--data '{"name":"www.example.com","ssl_certificate_id":"2b47ba9b-761a-492d-9a0c-000000000001"}'
```

```
HTTP 201 Created
```

```
{
"name": "www.example.com",
"created_at": "___created_at___",
"ssl_certificate_id": "2b47ba9b-761a-492d-9a0c-000000000001"
}
```
25 changes: 25 additions & 0 deletions src/actions/certificates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const addCertificate = ({ key, cert }) => ({
type: 'create-certificate',
endpoint: { name: 'certificates' },
method: 'POST',
body: { key, cert },
});

export const removeCertificate = certificateId => ({
type: 'remove-certificate',
endpoint: { name: 'certificate', params: { certificateId } },
method: 'DELETE',
});

export const addCertificateSNI = (ssl_certificate_id, name) => ({
type: 'add-certificate-sni',
endpoint: { name: 'certificate-snis' },
method: 'POST',
body: { name, ssl_certificate_id },
});

export const removeCertificateSNI = sniName => ({
type: 'remove-certificate-sni',
endpoint: { name: 'certificate-sni', params: { sniName } },
method: 'DELETE',
});
1 change: 1 addition & 0 deletions src/adminApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function createApi({ router, getPaginatedJson, ignoreConsumers }) {
fetchUpstreams: () => getPaginatedJson(router({name: 'upstreams'})),
fetchTargets: (upstreamId) => getPaginatedJson(router({name: 'upstream-targets', params: {upstreamId}})),
fetchTargetsV11Active: (upstreamId) => getPaginatedJson(router({name: 'upstream-targets-active', params: {upstreamId}})),
fetchCertificates: () => getPaginatedJson(router({name: 'certificates'})),

// this is very chatty call and doesn't change so its cached
fetchPluginSchemas: () => {
Expand Down
101 changes: 99 additions & 2 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ import {
updateUpstreamTarget
} from './actions/upstreams'

import {
addCertificate,
removeCertificate,
addCertificateSNI,
removeCertificateSNI,
} from './actions/certificates';

export const consumerAclSchema = {
id: 'group'
};
Expand Down Expand Up @@ -92,6 +99,7 @@ export default async function execute(config, adminApi, logger = () => {}) {
...upstreams(config.upstreams),
...apis(config.apis),
...globalPlugins(config.plugins),
...certificates(config.certificates),
...consumers(splitConsumersConfig.removed),
];

Expand Down Expand Up @@ -139,6 +147,18 @@ export function targets(upstreamName, targets) {
return targets.reduce((actions, target) => [...actions, _target(upstreamName, target)], []);
}

export function certificates(certificates = []) {
return certificates.reduce((actions, cert) => [...actions, _certificate(cert), ...certificatesSNIs(cert, cert.snis)], []);
}

export function certificatesSNIs(certificate, snis) {
if (certificate.ensure === 'removed') {
return [];
}

return snis.reduce((actions, sni) => [...actions, _sni(certificate, sni)], []);
}

function parseResponseContent(content) {
try {
return JSON.parse(content);
Expand Down Expand Up @@ -193,7 +213,7 @@ function _bindWorldState(adminApi) {
}
}

function _createWorld({apis, consumers, plugins, upstreams, _info: { version }}) {
function _createWorld({apis, consumers, plugins, upstreams, certificates, _info: { version }}) {
const world = {
getVersion: () => version,

Expand Down Expand Up @@ -411,7 +431,34 @@ function _createWorld({apis, consumers, plugins, upstreams, _info: { version }})

return targets[0];
}
}
},
getCertificate: ({ key }) => {
const certificate = certificates.find(x => x.key === key);

invariant(certificate, `Unable to find certificate for ${key.substr(1, 50)}`);

return certificate;
},

getCertificateId: certificate => {
return world.getCertificate(certificate)._info.id;
},

hasCertificate: ({ key }) => {
return certificates.some(x => x.key === key);
},

isCertificateUpToDate: certificate => {
const { key, cert } = world.getCertificate(certificate);

return certificate.key == key && certificate.cert == cert;
},

getCertificateSNIs: certificate => {
const { snis } = world.getCertificate(certificate);

return snis;
},
};

return world;
Expand Down Expand Up @@ -763,3 +810,53 @@ function validateUpstreamRequiredAttributes(upstream) {
throw Error(`Upstream name is required: ${JSON.stringify(upstream, null, ' ')}`);
}
}

const _certificate = certificate => {
validateEnsure(certificate.ensure);

return world => {
const identityClue = certificate.key.substr(1, 50);

if (certificate.ensure == 'removed') {
if (world.hasCertificate(certificate)) {
return removeCertificate(world.getCertificateId(certificate));
}

return noop({type: 'noop-certificate', identityClue});
}

if (world.hasCertificate(certificate)) {
if (world.isCertificateUpToDate(certificate)) {
return noop({type: 'noop-certificate', identityClue});
}

return updateCertificate(world.getCertificateId(certificate), certificate);
}

return addCertificate(certificate);
}
}

const _sni = (certificate, sni) => {
validateEnsure(sni.ensure);
invariant(sni.name, 'sni must have a name');

return world => {
const currentSNIs = world.getCertificateSNIs(certificate).map(x => x.name);
const hasSNI = currentSNIs.indexOf(sni.name) !== -1;

if (sni.ensure == 'removed') {
if (hasSNI) {
return removeCertificateSNI(sni.name);
}

return noop({type: 'noop-certificate-sni-removed', sni});
}

if (hasSNI) {
return noop({type: 'noop-certificate-sni', sni});
}

return addCertificateSNI(world.getCertificateId(certificate), sni.name);
};
}
12 changes: 11 additions & 1 deletion src/kongState.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ const fetchUpstreamsWithTargets = async ({ version, fetchUpstreams, fetchTargets
);
};

export default async ({fetchApis, fetchPlugins, fetchGlobalPlugins, fetchConsumers, fetchConsumerCredentials, fetchConsumerAcls, fetchUpstreams, fetchTargets, fetchTargetsV11Active, fetchKongVersion}) => {
const fetchCertificatesForVersion = async ({ version, fetchCertificates }) => {
if (semVer.lte(version, '0.10.0')) {
return Promise.resolve([]);
}

return await fetchCertificates();
};

export default async ({fetchApis, fetchPlugins, fetchGlobalPlugins, fetchConsumers, fetchConsumerCredentials, fetchConsumerAcls, fetchUpstreams, fetchTargets, fetchTargetsV11Active, fetchCertificates, fetchKongVersion}) => {
const version = await fetchKongVersion();
const apis = await fetchApis();
const apisWithPlugins = await Promise.all(apis.map(async item => {
Expand Down Expand Up @@ -63,12 +71,14 @@ export default async ({fetchApis, fetchPlugins, fetchGlobalPlugins, fetchConsume
});

const upstreamsWithTargets = await fetchUpstreamsWithTargets({ version, fetchUpstreams, fetchTargets: semVer.gte(version, '0.12.0') ? fetchTargets : fetchTargetsV11Active });
const certificates = await fetchCertificatesForVersion({ version, fetchCertificates });

return {
apis: apisWithPlugins,
consumers: consumersWithCredentialsAndAcls,
plugins: globalPlugins,
upstreams: upstreamsWithTargets,
certificates,
version,
};
};
3 changes: 3 additions & 0 deletions src/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export const screenLogger = createLogHandler({
'noop-credential': ({ credential, credentialIdName }) => console.log(`- credential ${credential.name.bold} with ${credentialIdName.bold}: ${credential.attributes[credentialIdName].bold} ${'is up to date'.bold.green}`),
'noop-upstream': ({ upstream }) => console.log(`upstream ${upstream.name.bold} ${'is up to date'.bold.green}`),
'noop-target': ({ target }) => console.log(`target ${target.target.bold} ${'is up to date'.bold.green}`),
'noop-certificate': ({ identityClue }) => console.log(`certificate ${identityClue}... ${'is up to date'.bold.green}`),
'noop-certificate-sni': ({ sni }) => console.log(`certificate sni ${sni.name} ${'is up to date'.bold.green}`),
'noop-certificate-sni-removed': ({ sni }) => console.log(`certificate sni ${sni.name} ${'is NOT present'.bold.green}`),

unknown: action => console.log('unknown action', action),
})(message.params),
Expand Down
Loading