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

Basic tls support for Ingress #20142

Merged
merged 1 commit into from
Feb 5, 2016
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions api/swagger-spec/v1beta1.json
Original file line number Diff line number Diff line change
Expand Up @@ -3616,6 +3616,13 @@
"$ref": "v1beta1.IngressBackend",
"description": "A default backend capable of servicing requests that don't match any rule. At least one of 'backend' or 'rules' must be specified. This field is optional to allow the loadbalancer controller or defaulting logic to specify a global default."
},
"tls": {
"type": "array",
"items": {
"$ref": "v1beta1.IngressTLS"
},
"description": "TLS configuration. Currently the Ingress only supports a single TLS port, 443, and assumes TLS termination. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension."
},
"rules": {
"type": "array",
"items": {
Expand Down Expand Up @@ -3643,6 +3650,23 @@
}
}
},
"v1beta1.IngressTLS": {
"id": "v1beta1.IngressTLS",
"description": "IngressTLS describes the transport layer security associated with an Ingress.",
"properties": {
"hosts": {
"type": "array",
"items": {
"type": "string"
},
"description": "Hosts are a list of hosts included in the TLS certificate. The values in this list must match the name/s used in the tlsSecret. Defaults to the wildcard host setting for the loadbalancer controller fulfilling this Ingress, if left unspecified."
},
"secretName": {
"type": "string",
"description": "SecretName is the name of the secret used to terminate SSL traffic on 443. Field is left optional to allow SSL routing based on SNI hostname alone. If the SNI host in a listener conflicts with the \"Host\" header field used by an IngressRule, the SNI host is used for termination and value of the Host header is used for routing."
}
}
},
"v1beta1.IngressRule": {
"id": "v1beta1.IngressRule",
"description": "IngressRule represents the rules mapping the paths under a specified host to the related backend services. Incoming requests are first evaluated for a host match, then routed to the backend associated with the matching IngressRuleValue.",
Expand Down
118 changes: 83 additions & 35 deletions docs/api-reference/extensions/v1beta1/definitions.html
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,13 @@ <h3 id="_v1beta1_ingressspec">v1beta1.IngressSpec</h3>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">tls</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">TLS configuration. Currently the Ingress only supports a single TLS port, 443, and assumes TLS termination. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_ingresstls">v1beta1.IngressTLS</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rules</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A list of host rules used to configure the Ingress. If unspecified, or no rule matches, all traffic is sent to the default backend.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
Expand Down Expand Up @@ -2631,6 +2638,40 @@ <h3 id="_v1_securitycontext">v1.SecurityContext</h3>
</tbody>
</table>

</div>
<div class="sect2">
<h3 id="_v1_flockervolumesource">v1.FlockerVolumeSource</h3>
<div class="paragraph">
<p>Represents a Flocker volume mounted by the Flocker agent. Flocker volumes do not support ownership management or SELinux relabeling.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">datasetName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: the volume name. This is going to be store on metadata &#8594; name on the payload for Flocker</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>

</div>
<div class="sect2">
<h3 id="_v1_awselasticblockstorevolumesource">v1.AWSElasticBlockStoreVolumeSource</h3>
Expand Down Expand Up @@ -2730,40 +2771,6 @@ <h3 id="_v1_persistentvolumeclaimvolumesource">v1.PersistentVolumeClaimVolumeSou
</tbody>
</table>

</div>
<div class="sect2">
<h3 id="_v1_flockervolumesource">v1.FlockerVolumeSource</h3>
<div class="paragraph">
<p>Represents a Flocker volume mounted by the Flocker agent. Flocker volumes do not support ownership management or SELinux relabeling.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">datasetName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Required: the volume name. This is going to be store on metadata &#8594; name on the payload for Flocker</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>

</div>
<div class="sect2">
<h3 id="_unversioned_listmeta">unversioned.ListMeta</h3>
Expand Down Expand Up @@ -4612,6 +4619,47 @@ <h3 id="_v1beta1_httpingresspath">v1beta1.HTTPIngressPath</h3>
</tbody>
</table>

</div>
<div class="sect2">
<h3 id="_v1beta1_ingresstls">v1beta1.IngressTLS</h3>
<div class="paragraph">
<p>IngressTLS describes the transport layer security associated with an Ingress.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">hosts</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Hosts are a list of hosts included in the TLS certificate. The values in this list must match the name/s used in the tlsSecret. Defaults to the wildcard host setting for the loadbalancer controller fulfilling this Ingress, if left unspecified.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">secretName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">SecretName is the name of the secret used to terminate SSL traffic on 443. Field is left optional to allow SSL routing based on SNI hostname alone. If the SNI host in a listener conflicts with the "Host" header field used by an IngressRule, the SNI host is used for termination and value of the Host header is used for routing.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>

</div>
<div class="sect2">
<h3 id="_v1beta1_subresourcereference">v1beta1.SubresourceReference</h3>
Expand Down Expand Up @@ -4886,7 +4934,7 @@ <h3 id="_any">any</h3>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-02-05 16:19:07 UTC
Last updated 2016-02-05 18:58:44 UTC
</div>
</div>
</body>
Expand Down
15 changes: 15 additions & 0 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2241,6 +2241,21 @@ const (

// SSHAuthPrivateKey is the key of the required SSH private key for SecretTypeSSHAuth secrets
SSHAuthPrivateKey = "ssh-privatekey"

// SecretTypeTLS contains information about a TLS client or server secret. It
// is primarily used with TLS termination of the Ingress resource, but may be
// used in other types.
//
// Required fields:
// - Secret.Data["tls.key"] - TLS private key.
// Secret.Data["tls.crt"] - TLS certificate.
// TODO: Consider supporting different formats, specifying CA/destinationCA.
SecretTypeTLS SecretType = "kubernetes.io/tls"

// TLSCertKey is the key for tls certificates in a TLS secert.
TLSCertKey = "tls.crt"
// TLSPrivateKeyKey is the key for the private key field in a TLS secret.
TLSPrivateKeyKey = "tls.key"
)

type SecretList struct {
Expand Down
15 changes: 15 additions & 0 deletions pkg/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2653,6 +2653,21 @@ const (

// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
DockerConfigKey = ".dockercfg"

// SecretTypeTLS contains information about a TLS client or server secret. It
// is primarily used with TLS termination of the Ingress resource, but may be
// used in other types.
//
// Required fields:
// - Secret.Data["tls.key"] - TLS private key.
// Secret.Data["tls.crt"] - TLS certificate.
// TODO: Consider supporting different formats, specifying CA/destinationCA.
SecretTypeTLS SecretType = "kubernetes.io/tls"

// TLSCertKey is the key for tls certificates in a TLS secert.
TLSCertKey = "tls.crt"
// TLSPrivateKeyKey is the key for the private key field in a TLS secret.
TLSPrivateKeyKey = "tls.key"
)

// SecretList is a list of Secret.
Expand Down
8 changes: 8 additions & 0 deletions pkg/api/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2083,6 +2083,14 @@ func ValidateSecret(secret *api.Secret) field.ErrorList {
break
}

case api.SecretTypeTLS:
if _, exists := secret.Data[api.TLSCertKey]; !exists {
allErrs = append(allErrs, field.Required(dataPath.Key(api.TLSCertKey), ""))
}
if _, exists := secret.Data[api.TLSPrivateKeyKey]; !exists {
allErrs = append(allErrs, field.Required(dataPath.Key(api.TLSPrivateKeyKey), ""))
}
// TODO: Verify that the key matches the cert.
default:
// no-op
}
Expand Down
46 changes: 46 additions & 0 deletions pkg/api/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4583,6 +4583,52 @@ func TestValidateEndpoints(t *testing.T) {
}
}

func TestValidateTLSSecret(t *testing.T) {
successCases := map[string]api.Secret{
"emtpy certificate chain": {
ObjectMeta: api.ObjectMeta{Name: "tls-cert", Namespace: "namespace"},
Data: map[string][]byte{
api.TLSCertKey: []byte("public key"),
api.TLSPrivateKeyKey: []byte("private key"),
},
},
}
for k, v := range successCases {
if errs := ValidateSecret(&v); len(errs) != 0 {
t.Errorf("Expected success for %s, got %v", k, errs)
}
}
errorCases := map[string]struct {
secrets api.Secret
errorType field.ErrorType
errorDetail string
}{
"missing public key": {
secrets: api.Secret{
ObjectMeta: api.ObjectMeta{Name: "tls-cert"},
Data: map[string][]byte{
api.TLSCertKey: []byte("public key"),
},
},
errorType: "FieldValueRequired",
},
"missing private key": {
secrets: api.Secret{
ObjectMeta: api.ObjectMeta{Name: "tls-cert"},
Data: map[string][]byte{
api.TLSCertKey: []byte("public key"),
},
},
errorType: "FieldValueRequired",
},
}
for k, v := range errorCases {
if errs := ValidateSecret(&v.secrets); len(errs) == 0 || errs[0].Type != v.errorType || !strings.Contains(errs[0].Detail, v.errorDetail) {
t.Errorf("[%s] Expected error type %s with detail %q, got %v", k, v.errorType, v.errorDetail, errs)
}
}
}

func TestValidateSecurityContext(t *testing.T) {
priv := false
var runAsUser int64 = 1
Expand Down