Add capability for the v1/connect/ca/roots endpoint to return a PEM encoded certificate chain (#8774)
Co-authored-by: R.B. Boyer <rb@hashicorp.com>
This commit is contained in:
parent
d2f09ca306
commit
891d05fada
4
.changelog/8774.txt
Normal file
4
.changelog/8774.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
```release-note:improvement
|
||||
api: The `v1/connect/ca/roots` endpoint now accepts a `pem=true` query parameter and will return a PEM encoded certificate chain of
|
||||
all the certificates that would normally be in the JSON version of the response.
|
||||
```
|
|
@ -3,6 +3,7 @@ package agent
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/consul/agent/consul"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
|
@ -15,13 +16,39 @@ func (s *HTTPHandlers) ConnectCARoots(resp http.ResponseWriter, req *http.Reques
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
pemResponse := false
|
||||
if pemParam := req.URL.Query().Get("pem"); pemParam != "" {
|
||||
val, err := strconv.ParseBool(pemParam)
|
||||
if err != nil {
|
||||
return nil, BadRequestError{Reason: "The 'pem' query parameter must be a boolean value"}
|
||||
}
|
||||
pemResponse = val
|
||||
}
|
||||
|
||||
var reply structs.IndexedCARoots
|
||||
defer setMeta(resp, &reply.QueryMeta)
|
||||
if err := s.agent.RPC("ConnectCA.Roots", &args, &reply); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
if !pemResponse {
|
||||
return reply, nil
|
||||
}
|
||||
|
||||
// defined in RFC 8555 and registered with the IANA
|
||||
resp.Header().Set("Content-Type", "application/pem-certificate-chain")
|
||||
for _, root := range reply.Roots {
|
||||
if _, err := resp.Write([]byte(root.RootCert)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, intermediate := range root.IntermediateCerts {
|
||||
if _, err := resp.Write([]byte(intermediate)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// /v1/connect/ca/configuration
|
||||
|
|
|
@ -2,6 +2,8 @@ package agent
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
@ -258,3 +260,34 @@ func TestConnectCAConfig(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectCARoots_PEMEncoding(t *testing.T) {
|
||||
primary := NewTestAgent(t, "")
|
||||
defer primary.Shutdown()
|
||||
testrpc.WaitForActiveCARoot(t, primary.RPC, "dc1", nil)
|
||||
|
||||
secondary := NewTestAgent(t, `
|
||||
primary_datacenter = "dc1"
|
||||
datacenter = "dc2"
|
||||
retry_join_wan = ["`+primary.Config.SerfBindAddrWAN.String()+`"]
|
||||
`)
|
||||
defer secondary.Shutdown()
|
||||
testrpc.WaitForActiveCARoot(t, secondary.RPC, "dc2", nil)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/v1/connect/ca/roots?pem=true", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
obj, err := secondary.srv.ConnectCARoots(recorder, req)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, obj, "Endpoint returned an object for serialization when it should have returned nil and written to the responses")
|
||||
resp := recorder.Result()
|
||||
require.Equal(t, resp.Header.Get("Content-Type"), "application/pem-certificate-chain")
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
|
||||
require.True(t, pool.AppendCertsFromPEM(data))
|
||||
// expecting the root cert from dc1 and an intermediate in dc2
|
||||
require.Len(t, pool.Subjects(), 2)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,13 @@ The table below shows this endpoint's support for
|
|||
| ---------------- | ----------------- | ------------- | ------------ |
|
||||
| `YES` | `all` | `none` | `none` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `pem` `(boolean: false)` - Specifies that the return body should be a PEM encoded
|
||||
certificate chain suitable for use by applications needing to trust Connect CA
|
||||
signed certificates. The Content-Type will be set to `application/pem-certificate-chain`
|
||||
to indicate the format of the response.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```shell-session
|
||||
|
@ -65,6 +72,39 @@ $ curl \
|
|||
}
|
||||
```
|
||||
|
||||
### Sample PEM Encoded Response
|
||||
|
||||
```
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICDzCCAbWgAwIBAgIBCDAKBggqhkjOPQQDAjAxMS8wLQYDVQQDEyZwcmktMWNq
|
||||
OHphbW0uY29uc3VsLmNhLjA3OTMzYTEzLmNvbnN1bDAeFw0yMDEwMDgxOTQ4MzZa
|
||||
Fw0zMDEwMDgxOTQ4MzZaMDExLzAtBgNVBAMTJnByaS0xY2o4emFtbS5jb25zdWwu
|
||||
Y2EuMDc5MzNhMTMuY29uc3VsMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDCkT
|
||||
IIxSDhA3XCKIuDcj4s9IVjf0NQT6QHPAzFBb964/4fTtX/J8x2n6A1lOXowFIWtx
|
||||
GvAD/IJF74zn5ZA/wqOBvTCBujAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
|
||||
AwEB/zApBgNVHQ4EIgQguPlAkrIkOnLr9+8DZ4afZWrYZUd2LB6nMJP72jDVxmcw
|
||||
KwYDVR0jBCQwIoAguPlAkrIkOnLr9+8DZ4afZWrYZUd2LB6nMJP72jDVxmcwPwYD
|
||||
VR0RBDgwNoY0c3BpZmZlOi8vMDc5MzNhMTMtYTYyYi1iZTkwLTQ0ZjEtZGVkOWE2
|
||||
NjczNzZlLmNvbnN1bDAKBggqhkjOPQQDAgNIADBFAiEA0ExkvLESG1I1TMFVronr
|
||||
2fjoORukgzBgRMbWAEC2DJ0CIACsxeFS6tprHiRv4cEa2Md75h1iIisb2V2U7dvY
|
||||
Z7Rr
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICEzCCAbigAwIBAgIBCTAKBggqhkjOPQQDAjAxMS8wLQYDVQQDEyZwcmktMWNq
|
||||
OHphbW0uY29uc3VsLmNhLjA3OTMzYTEzLmNvbnN1bDAeFw0yMDEwMDgxOTQ3Mzda
|
||||
Fw0yMTEwMDgxOTQ3MzdaMDExLzAtBgNVBAMTJnNlYy0xbmIxMHZ0by5jb25zdWwu
|
||||
Y2EuMDc5MzNhMTMuY29uc3VsMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9zWs
|
||||
UxEYvLZUySoflz6e+HqLcaXM8heNRRkAiLiGkmn6nan6olnnrVBLyHAfHaHWJQ9W
|
||||
wI8HwSZf0g4Ms16LWKOBwDCBvTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgw
|
||||
BgEB/wIBADApBgNVHQ4EIgQg+csK9Sg6odIfLLk3aiRY2OB4O0DiOa1XRTVdOVDE
|
||||
t6QwKwYDVR0jBCQwIoAguPlAkrIkOnLr9+8DZ4afZWrYZUd2LB6nMJP72jDVxmcw
|
||||
PwYDVR0RBDgwNoY0c3BpZmZlOi8vMDc5MzNhMTMtYTYyYi1iZTkwLTQ0ZjEtZGVk
|
||||
OWE2NjczNzZlLmNvbnN1bDAKBggqhkjOPQQDAgNJADBGAiEAqJ60KJepAP4Xe4Ak
|
||||
5UYB1huu/B8Lyz5yEYUpUplgdD4CIQCrrkoXoD4SGJ4HaIjy6a5eNf3YkhLpmbXO
|
||||
6DL6FXVa1Q==
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
## Get CA Configuration
|
||||
|
||||
This endpoint returns the current CA configuration.
|
||||
|
|
Loading…
Reference in a new issue