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

Lose snis when updating certificate #356

Closed
tinhhn opened this issue Apr 28, 2021 · 6 comments · Fixed by #386
Closed

Lose snis when updating certificate #356

tinhhn opened this issue Apr 28, 2021 · 6 comments · Fixed by #386

Comments

@tinhhn
Copy link

tinhhn commented Apr 28, 2021

I have a certificate with a sni (*.example.xzy):
Screenshot from 2021-04-28 09-40-29

But it loses snis when I update certificate (for renewal):
Screenshot from 2021-04-28 09-44-09

I use the commands below to update certificate:

deck ping
deck -s kong/ validate
deck -s kong/ diff
deck -s kong/ sync

Here is my Kong Declarative configuration for certificate:

certificates:
- id: ecd612c1-ec71-4311-85b3-96226ae79e6c
  cert: |-
    -----BEGIN CERTIFICATE-----
    #hidden
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    #hidden
    -----END CERTIFICATE-----
  key: |-
    -----BEGIN PRIVATE KEY-----
    #hidden
    -----END PRIVATE KEY-----
  snis:
  - name: '*.example.xzy'

What I missed? Thanks in advance!

@rainest
Copy link
Contributor

rainest commented May 4, 2021

Can you confirm your Kong and decK versions, and provide an example file (with a dummy certificate) that demonstrates the issue? I was not able to replicate this:

09:24:24-0700 yagody $ deck reset         
This will delete all configuration from Kong's database.
> Are you sure? y

09:25:29-0700 yagody $ deck sync -s cert.yaml
creating certificate 1bac12f4-9baf-4b1e-b35b-3f0975e1f5f3
creating sni *.example.com
Summary:
  Created: 2
  Updated: 0
  Deleted: 0

09:25:46-0700 yagody $ http localhost:8001/snis
HTTP/1.1 200 OK
{
    "data": [
        {
            "certificate": {
                "id": "1bac12f4-9baf-4b1e-b35b-3f0975e1f5f3"
            },
            "created_at": 1620145546,
            "id": "6c9b8723-3623-4990-9909-169d17479b8f",
            "name": "*.example.com",
            "tags": null
        }
    ],
    "next": null
}

cert.yaml.txt

@tinhhn
Copy link
Author

tinhhn commented May 6, 2021

Thanks for response!

Can you confirm your Kong and decK versions

Kong version: 2.3.3 (and same problem with 2.2.1)
decK version: v1.3.0 (kong/deck:v1.3.0)

provide an example file (with a dummy certificate) that demonstrates the issue

I use the example file that you provided above:

_format_version: "1.1"
certificates:
- cert: |-
    -----BEGIN CERTIFICATE-----
    MIICaDCCAg+gAwIBAgIUAeEWi1LVOc3jfGM4D9s7ouu5gn8wCgYIKoZIzj0EAwIw
    fDELMAkGA1UEBhMCVVMxFDASBgNVBAcTC01pbm5lYXBvbGlzMRQwEgYDVQQKEwtZ
    YWsgU2hhdmluZzEMMAoGA1UECxMDV29vMTMwMQYDVQQDEypZYWsgU2hhdmVzIEZh
    a2UgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTgwMzE1MjIwNDAwWhcN
    NDgwMzA3MjIwNDAwWjCBhDELMAkGA1UEBhMCVVMxFDASBgNVBAcTC01pbm5lYXBv
    bGlzMRQwEgYDVQQKEwtZYWsgU2hhdmluZzEMMAoGA1UECxMDV29vMTswOQYDVQQD
    EzJZYWsgU2hhdmVzIEZha2UgSW50ZXJtZWRpYXRlIENlcnRpZmljYXRlIEF1dGhv
    cml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJe0dIIz6uDl01LTg67pzOq3
    m2ZHyHipJxEsvvkOGc7+dB2bmnZQM//S2ut+hfeTg9HvAltgKdIs/UznHFX3Pbqj
    ZjBkMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEEMB0GA1UdDgQW
    BBTY2wo2AccpUoaeTvBQj4ceDMa6lDAfBgNVHSMEGDAWgBR8k3wJHVo2QJzR9Cb7
    /OJb/bcsNzAKBggqhkjOPQQDAgNHADBEAiAns+fWYX8O6lxxKH1Dx/WnGm4TR3oV
    s/2S9VZHLCuNjgIgJwNpC9EoCRjwmQLEPPj3B2N3+FEgl47VKRjJQzXFr3w=
    -----END CERTIFICATE-----
  id: 1bac12f4-9baf-4b1e-b35b-3f0975e1f5f3
  key: |-
    -----BEGIN EC PRIVATE KEY-----
    MHcCAQEEIMn+gMgBbIX77RLgJMFvbHJ1VIBv+UQmtxxjSLk29SjhoAoGCCqGSM49
    AwEHoUQDQgAEl7R0gjPq4OXTUtODrunM6rebZkfIeKknESy++Q4Zzv50HZuadlAz
    /9La636F95OD0e8CW2Ap0iz9TOccVfc9ug==
    -----END EC PRIVATE KEY-----
  snis:
  - name: '*.example.com'

Firstly, there is no cert:
Screenshot from 2021-05-06 14-11-21

Then I run deck sync to create new cert, the sni exists:
Screenshot from 2021-05-06 14-09-47

But when I change the cert and update with deck sync, the sni lost:

_format_version: "1.1"
certificates:
- cert: |-
    -----BEGIN CERTIFICATE-----
    MIICaDCCAg+gAwIBAgIUAeEWi1LVOc3jfGM4D9s7ouu5gn8wCgYIKoZIzj0EAwIw
    fDELMAkGA1UEBhMCVVMxFDASBgNVBAcTC01pbm5lYXBvbGlzMRQwEgYDVQQKEwtZ
    YWsgU2hhdmluZzEMMAoGA1UECxMDV29vMTMwMQYDVQQDEypZYWsgU2hhdmVzIEZh
    a2UgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTgwMzE1MjIwNDAwWhcN
    NDgwMzA3MjIwNDAwWjCBhDELMAkGA1UEBhMCVVMxFDASBgNVBAcTC01pbm5lYXBv
    bGlzMRQwEgYDVQQKEwtZYWsgU2hhdmluZzEMMAoGA1UECxMDV29vMTswOQYDVQQD
    EzJZYWsgU2hhdmVzIEZha2UgSW50ZXJtZWRpYXRlIENlcnRpZmljYXRlIEF1dGhv
    cml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJe0dIIz6uDl01LTg67pzOq3
    m2ZHyHipJxEsvvkOGc7+dB2bmnZQM//S2ut+hfeTg9HvAltgKdIs/UznHFX3Pbqj
    ZjBkMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEEMB0GA1UdDgQW
    BBTY2wo2AccpUoaeTvBQj4ceDMa6lDAfBgNVHSMEGDAWgBR8k3wJHVo2QJzR9Cb7
    /OJb/bcsNzAKBggqhkjOPQQDAgNHADBEAiAns+fWYX8O6lxxKH1Dx/WnGm4TR3oV
    s/2S9VZHLCuNjgIgJwNpC9EoCRjwmQLEPPj3B2N3+FEgl47VKRjJQzXFr3w=
    -----END CERTIFICATE-----
  id: 1bac12f4-9baf-4b1e-b35b-3f0975e1f5f3
  key: |-
    -----BEGIN EC PRIVATE KEY-----
    MHcCAQEEIMn+gMgBbIX77RLgJMFvbHJ1VIBv+UQmtxxjSLk29SjhoAoGCCqGSM49
    AwEHoUQDQgAEl7R0gjPq4OXTUtODrunM6rebZkfIeKknESy++Q4Zzv50HZuadlAz
    /9La636F95OD0e8CW2Ap0iz9TOccVfc9uh==
    -----END EC PRIVATE KEY-----
  snis:
  - name: '*.example.com'

Screenshot from 2021-05-06 14-10-18

@rainest
Copy link
Contributor

rainest commented May 7, 2021

Ah, you have to modify it, not just run sync repeatedly. Current workaround is to sync again after syncing the modified certificate: this will detect the missing SNI and re-add it.

This happens because we remove SNIs from certificate objects read from a state:
https://github.com/Kong/deck/blob/v1.6.0/dump/dump.go#L349
https://github.com/Kong/deck/blob/v1.6.0/file/builder.go#L92-L112

and treat the SNIs as separate objects. The PUT requests that we use to update certificates, however, then include an empty SNIs array, and Kong actually deletes any existing SNIs when you do this.

There are two approaches to handle this:

  • patch_certificate.diff.txt simply uses a PATCH instead. We don't currently do this because that can leave deleted configuration in place. This is mostly benign for certificates because most of their fields either must be set or are handled elsewhere (deleted SNIs are handled because we treat them as separate objects and issue update commands for them independently), but it does affect tags: a PATCH that includes an empty tag set will not remove existing tags.
  • include_snis.diff.txt doesn't strip SNIs from certificate objects, so the PUT requests don't destroy them. This avoids the PATCH issue, and from initial testing doesn't appear to cause new issues, but I'm not sure if it'd somehow interfere with independent SNI operations.

@tinhhn
Copy link
Author

tinhhn commented May 7, 2021

There are two approaches to handle this

Beside of the issues (may happen) that you mentioned. Currently, I don't want to rebuild decK.
So I take a look at the workaround (run a second deck sync cmd) and it works well.

Thanks for the clarification!

@tinhhn tinhhn closed this as completed May 7, 2021
@rainest
Copy link
Contributor

rainest commented May 7, 2021

To clarify, we intend to fix the issue with one or the other solution and just haven't decided.

@rainest rainest reopened this May 7, 2021
rainest pushed a commit that referenced this issue May 14, 2021
When decK must update a certificate, retrieve the current certificate's
set of SNIs, convert them to strings, and set these on the updated
certificate.

Certificate and SNI objects have a special relationship. A PUT request
(which we use for updates) with a certificate that contains no SNI
children will in fact delete any existing SNI objects associated with
that certificate, rather than leaving them as-is. Because decK considers
SNIs separate objects and strips SNI child objects from certificate
objects, updates to other certificate fields will PUT a certificate with
no SNIs and inadvertently delete existing SNIs.

Not stripping SNIs from certificate objects in general presents its own
issues, as decK will attempt to operate on both objects and generate
conflicts.

To work around these issues, this change sets SNIs on certificates ONLY
during update requests using the current certificate's SNI list. If
there are changes to the SNIs, subsequent actions on the SNI objects
will handle those.

Fix #356
@rainest
Copy link
Contributor

rainest commented May 14, 2021

Alright, further testing on the include SNIs option indicates that it causes a bunch of conflicts when performing operations that do modify SNIs.

The PATCH option is complicated and requires changes to go-kong to completely work correctly, so instead, new option 3: #386

rainest pushed a commit that referenced this issue May 17, 2021
When decK must update a certificate, retrieve the current certificate's
set of SNIs, convert them to strings, and set these on the updated
certificate.

Certificate and SNI objects have a special relationship. A PUT request
(which we use for updates) with a certificate that contains no SNI
children will in fact delete any existing SNI objects associated with
that certificate, rather than leaving them as-is. Because decK considers
SNIs separate objects and strips SNI child objects from certificate
objects, updates to other certificate fields will PUT a certificate with
no SNIs and inadvertently delete existing SNIs.

Not stripping SNIs from certificate objects in general presents its own
issues, as decK will attempt to operate on both objects and generate
conflicts.

To work around these issues, this change sets SNIs on certificates ONLY
during update requests using the current certificate's SNI list. If
there are changes to the SNIs, subsequent actions on the SNI objects
will handle those.

Fix #356
rainest pushed a commit that referenced this issue May 18, 2021
When decK must update a certificate, retrieve the current certificate's
set of SNIs, convert them to strings, and set these on the updated
certificate.

Certificate and SNI objects have a special relationship. A PUT request
(which we use for updates) with a certificate that contains no SNI
children will in fact delete any existing SNI objects associated with
that certificate, rather than leaving them as-is. Because decK considers
SNIs separate objects and strips SNI child objects from certificate
objects, updates to other certificate fields will PUT a certificate with
no SNIs and inadvertently delete existing SNIs.

Not stripping SNIs from certificate objects in general presents its own
issues, as decK will attempt to operate on both objects and generate
conflicts.

To work around these issues, this change sets SNIs on certificates ONLY
during update requests using the current certificate's SNI list. If
there are changes to the SNIs, subsequent actions on the SNI objects
will handle those.

Fix #356
rainest pushed a commit that referenced this issue May 18, 2021
When decK must update a certificate, retrieve the current certificate's
set of SNIs, convert them to strings, and set these on the updated
certificate.

Certificate and SNI objects have a special relationship. A PUT request
(which we use for updates) with a certificate that contains no SNI
children will in fact delete any existing SNI objects associated with
that certificate, rather than leaving them as-is. Because decK considers
SNIs separate objects and strips SNI child objects from certificate
objects, updates to other certificate fields will PUT a certificate with
no SNIs and inadvertently delete existing SNIs.

Not stripping SNIs from certificate objects in general presents its own
issues, as decK will attempt to operate on both objects and generate
conflicts.

To work around these issues, this change sets SNIs on certificates ONLY
during update requests using the current certificate's SNI list. If
there are changes to the SNIs, subsequent actions on the SNI objects
will handle those.

Fix #356
AntoineJac pushed a commit that referenced this issue Jan 23, 2024
When decK must update a certificate, retrieve the current certificate's
set of SNIs, convert them to strings, and set these on the updated
certificate.

Certificate and SNI objects have a special relationship. A PUT request
(which we use for updates) with a certificate that contains no SNI
children will in fact delete any existing SNI objects associated with
that certificate, rather than leaving them as-is. Because decK considers
SNIs separate objects and strips SNI child objects from certificate
objects, updates to other certificate fields will PUT a certificate with
no SNIs and inadvertently delete existing SNIs.

Not stripping SNIs from certificate objects in general presents its own
issues, as decK will attempt to operate on both objects and generate
conflicts.

To work around these issues, this change sets SNIs on certificates ONLY
during update requests using the current certificate's SNI list. If
there are changes to the SNIs, subsequent actions on the SNI objects
will handle those.

Fix #356
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants