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

feat: Implement setting common TLS parameters in ClientTrafficPolicy #2297

Merged
merged 16 commits into from
Jan 9, 2024
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
29 changes: 16 additions & 13 deletions api/v1alpha1/tls_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

package v1alpha1

// +kubebuilder:validation:XValidation:rule="has(self.minVersion) && self.minVersion == 'v1_3' ? !has(self.ciphers) : true", message="setting ciphers has no effect if the minimum possible TLS version is 1.3"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add some test for these in a separated PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added #2424

// +kubebuilder:validation:XValidation:rule="has(self.minVersion) && has(self.maxVersion) ? {\"Auto\":0,\"v1_1\":1,\"v1_2\":2,\"v1_3\":3}[self.minVersion] <= {\"v1_1\":1,\"v1_2\":2,\"v1_3\":3,\"Auto\":4}[self.maxVersion] : !has(self.minVersion) && has(self.maxVersion) ? 2 <= {\"v1_1\":1,\"v1_2\":2,\"v1_3\":3,\"Auto\":4}[self.maxVersion] : true", message="minVersion must be smaller or equal to maxVersion"
// +kubebuilder:validation:XValidation:rule="has(self.minVersion) && self.minVersion == '1.3' ? !has(self.ciphers) : true", message="setting ciphers has no effect if the minimum possible TLS version is 1.3"
// +kubebuilder:validation:XValidation:rule="has(self.minVersion) && has(self.maxVersion) ? {\"Auto\":0,\"1.0\":1,\"1.1\":2,\"1.2\":3,\"1.3\":4}[self.minVersion] <= {\"1.0\":1,\"1.1\":2,\"1.2\":3,\"1.3\":4,\"Auto\":5}[self.maxVersion] : !has(self.minVersion) && has(self.maxVersion) ? 3 <= {\"1.0\":1,\"1.1\":2,\"1.2\":3,\"1.3\":4,\"Auto\":5}[self.maxVersion] : true", message="minVersion must be smaller or equal to maxVersion"
type TLSSettings struct {

// Min specifies the minimal TLS protocol version to allow.
Expand Down Expand Up @@ -57,43 +57,46 @@ type TLSSettings struct {
SignatureAlgorithms []string `json:"signatureAlgorithms,omitempty"`

// ALPNProtocols supplies the list of ALPN protocols that should be
// exposed by the listener. By default http/2 and http/1.1 are enabled.
// exposed by the listener. By default h2 and http/1.1 are enabled.
//
// Supported values are:
// - http/1.0
// - http/1.1
// - http/2
// - h2
//
// +optional
ALPNProtocols []ALPNProtocol `json:"alpnProtocols,omitempty"`
}

// ALPNProtocol specifies the protocol to be negotiated using ALPN
// +kubebuilder:validation:Enum=http/1.0;http/1.1;http/2
// +kubebuilder:validation:Enum=http/1.0;http/1.1;h2
type ALPNProtocol string

// When adding ALPN constants, they must be values that are defined
// in the IANA registry for ALPN identification sequences
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
const (
// HTTPProtocolVersion1_0 specifies that HTTP/1.0 should be negotiable with ALPN
HTTPProtocolVersion1_0 ALPNProtocol = "http/1.0"
// HTTPProtocolVersion1_1 specifies that HTTP/1.1 should be negotiable with ALPN
HTTPProtocolVersion1_1 ALPNProtocol = "http/1.1"
// HTTPProtocolVersion2 specifies that HTTP/2 should be negotiable with ALPN
HTTPProtocolVersion2 ALPNProtocol = "http/2"
HTTPProtocolVersion2 ALPNProtocol = "h2"
)

// TLSVersion specifies the TLS version
// +kubebuilder:validation:Enum=Auto;v1_0;v1_1;v1_2;v1_3
// +kubebuilder:validation:Enum=Auto;"1.0";"1.1";"1.2";"1.3"
type TLSVersion string

const (
// TLSAuto allows Envoy to choose the optimal TLS Version
TLSAuto TLSVersion = "Auto"
// TLSv1_0 specifies TLS version 1.0
TLSv10 TLSVersion = "v1_0"
// TLSv1_1 specifies TLS version 1.1
TLSv11 TLSVersion = "v1_1"
// TLS1.0 specifies TLS version 1.0
TLSv10 TLSVersion = "1.0"
// TLS1.1 specifies TLS version 1.1
TLSv11 TLSVersion = "1.1"
// TLSv1.2 specifies TLS version 1.2
TLSv12 TLSVersion = "v1_2"
TLSv12 TLSVersion = "1.2"
// TLSv1.3 specifies TLS version 1.3
TLSv13 TLSVersion = "v1_3"
TLSv13 TLSVersion = "1.3"
)
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,16 @@ spec:
properties:
alpnProtocols:
description: "ALPNProtocols supplies the list of ALPN protocols
that should be exposed by the listener. By default http/2 and
http/1.1 are enabled. \n Supported values are: - http/1.0 -
http/1.1 - http/2"
that should be exposed by the listener. By default h2 and http/1.1
are enabled. \n Supported values are: - http/1.0 - http/1.1
- h2"
items:
description: ALPNProtocol specifies the protocol to be negotiated
using ALPN
enum:
- http/1.0
- http/1.1
- http/2
- h2
type: string
type: array
ciphers:
Expand Down Expand Up @@ -180,20 +180,20 @@ spec:
allow \n The default is TLS 1.3 if this is not specified."
enum:
- Auto
- v1_0
- v1_1
- v1_2
- v1_3
- "1.0"
- "1.1"
- "1.2"
- "1.3"
type: string
minVersion:
description: "Min specifies the minimal TLS protocol version to
allow. \n The default is TLS 1.2 if this is not specified."
enum:
- Auto
- v1_0
- v1_1
- v1_2
- v1_3
- "1.0"
- "1.1"
- "1.2"
- "1.3"
type: string
signatureAlgorithms:
description: SignatureAlgorithms specifies which signature algorithms
Expand All @@ -205,12 +205,12 @@ spec:
x-kubernetes-validations:
- message: setting ciphers has no effect if the minimum possible TLS
version is 1.3
rule: 'has(self.minVersion) && self.minVersion == ''v1_3'' ? !has(self.ciphers)
rule: 'has(self.minVersion) && self.minVersion == ''1.3'' ? !has(self.ciphers)
: true'
- message: minVersion must be smaller or equal to maxVersion
rule: 'has(self.minVersion) && has(self.maxVersion) ? {"Auto":0,"v1_1":1,"v1_2":2,"v1_3":3}[self.minVersion]
<= {"v1_1":1,"v1_2":2,"v1_3":3,"Auto":4}[self.maxVersion] : !has(self.minVersion)
&& has(self.maxVersion) ? 2 <= {"v1_1":1,"v1_2":2,"v1_3":3,"Auto":4}[self.maxVersion]
rule: 'has(self.minVersion) && has(self.maxVersion) ? {"Auto":0,"1.0":1,"1.1":2,"1.2":3,"1.3":4}[self.minVersion]
<= {"1.0":1,"1.1":2,"1.2":3,"1.3":4,"Auto":5}[self.maxVersion]
: !has(self.minVersion) && has(self.maxVersion) ? 3 <= {"1.0":1,"1.1":2,"1.2":3,"1.3":4,"Auto":5}[self.maxVersion]
: true'
required:
- targetRef
Expand Down
45 changes: 45 additions & 0 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ func (t *Translator) translateClientTrafficPolicyForListener(policySpec *egv1a1.
proxyListenerIR.HTTP3 = &ir.HTTP3Settings{}
}
}

// Translate TLS parameters
translateListenerTLSParameters(policySpec.TLS, httpIR)
}
}

Expand Down Expand Up @@ -359,3 +362,45 @@ func translateListenerSuppressEnvoyHeaders(suppressEnvoyHeaders *bool, httpIR *i
httpIR.SuppressEnvoyHeaders = *suppressEnvoyHeaders
}
}

func translateListenerTLSParameters(tlsParams *egv1a1.TLSSettings, httpIR *ir.HTTPListener) {
// Return if this listener isn't a TLS listener. There has to be
// at least one certificate defined, which would cause httpIR to
// have a TLS structure.
if httpIR.TLS == nil {
return
}
// Make sure that the negotiated TLS protocol version is as expected if TLS is used,
// regardless of if TLS parameters were used in the ClientTrafficPolicy or not
httpIR.TLS.MinVersion = ptr.To(ir.TLSv12)
httpIR.TLS.MaxVersion = ptr.To(ir.TLSv13)
// If HTTP3 is enabled, the ALPN protocols array should be hardcoded
arkodg marked this conversation as resolved.
Show resolved Hide resolved
// for HTTP3
if httpIR.HTTP3 != nil {
httpIR.TLS.ALPNProtocols = []string{"h3"}
} else if tlsParams != nil && len(tlsParams.ALPNProtocols) > 0 {
httpIR.TLS.ALPNProtocols = make([]string, len(tlsParams.ALPNProtocols))
Copy link
Contributor

@arkodg arkodg Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldnt this line

httpIR.TLS.ALPNProtocols = make([]string, len(tlsParams.ALPNProtocols))

be under if tlsParams.ALPNProtocols != nil

else it will end up resetting the value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

for i := range tlsParams.ALPNProtocols {
httpIR.TLS.ALPNProtocols[i] = string(tlsParams.ALPNProtocols[i])
}
}
// Return early if not set
if tlsParams == nil {
return
}
if tlsParams.MinVersion != nil {
httpIR.TLS.MinVersion = ptr.To(ir.TLSVersion(*tlsParams.MinVersion))
}
if tlsParams.MaxVersion != nil {
httpIR.TLS.MaxVersion = ptr.To(ir.TLSVersion(*tlsParams.MaxVersion))
}
if len(tlsParams.Ciphers) > 0 {
httpIR.TLS.Ciphers = tlsParams.Ciphers
}
if len(tlsParams.ECDHCurves) > 0 {
httpIR.TLS.ECDHCurves = tlsParams.ECDHCurves
}
if len(tlsParams.SignatureAlgorithms) > 0 {
httpIR.TLS.SignatureAlgorithms = tlsParams.SignatureAlgorithms
}
}
8 changes: 5 additions & 3 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,14 +391,16 @@ func irRouteDestinationName(route RouteContext, ruleIdx int) string {
return fmt.Sprintf("%srule/%d", irRoutePrefix(route), ruleIdx)
}

func irTLSConfigs(tlsSecrets []*v1.Secret) []*ir.TLSListenerConfig {
func irTLSConfigs(tlsSecrets []*v1.Secret) *ir.TLSConfig {
if len(tlsSecrets) == 0 {
return nil
}

tlsListenerConfigs := make([]*ir.TLSListenerConfig, len(tlsSecrets))
tlsListenerConfigs := &ir.TLSConfig{
Certificates: make([]ir.TLSCertificate, len(tlsSecrets)),
}
for i, tlsSecret := range tlsSecrets {
tlsListenerConfigs[i] = &ir.TLSListenerConfig{
tlsListenerConfigs.Certificates[i] = ir.TLSCertificate{
Name: irTLSListenerConfigName(tlsSecret),
ServerCertificate: tlsSecret.Data[v1.TLSCertKey],
PrivateKey: tlsSecret.Data[v1.TLSPrivateKeyKey],
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
11 changes: 8 additions & 3 deletions internal/gatewayapi/testdata/clienttrafficpolicy-http3.out.yaml
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ xdsIR:
name: ""
prefix: /
tls:
- name: envoy-gateway-tls-secret-1
privateKey: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
serverCertificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNxRENDQVpBQ0NRREVNZ1lZblFyQ29EQU5CZ2txaGtpRzl3MEJBUXNGQURBV01SUXdFZ1lEVlFRRERBdG0KYjI4dVltRnlMbU52YlRBZUZ3MHlNekF4TURVeE16UXpNalJhRncweU5EQXhNRFV4TXpRek1qUmFNQll4RkRBUwpCZ05WQkFNTUMyWnZieTVpWVhJdVkyOXRNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDCkFRRUFuZEh6d21wS2NUSUViamhGZ2RXd1RSTjc1Y3A4b3VsWnhMMUdydlI2SXc3ejdqaTBSNFcvTm85bkdmOU0KWVAyQ1JqaXN6NTFtd3hTeGVCcm9jTGVBK21reGkxK2lEdk5kQytyU0x4MTN6RUxTQ25xYnVzUHM3bUdmSlpxOAo5TGhlbmx5bzQzaDVjYTZINUxqTXd1L1JHVWlGMzFYck5yaVlGQlB2RTJyQitkd24vTkVrUTRoOFJxcXlwcmtuCkYvcWM5Sk1ZQVlGRld1VkNwa0lFbmRYMUN5dlFOT2FkZmN2cmd6dDV2SmwwT2kxQWdyaU5hWGJFUEdudWY3STQKcXBCSEdVWE5lMVdsOVdlVklxS1g0T2FFWERWQzZGQzdHOHptZWVMVzFBa1lFVm5pcFg2b1NCK0JjL1NIVlZOaApzQkxSbXRuc3pmTnRUMlFyZCttcGt4ODBaUUlEQVFBQk1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ1VKOElDCkJveUVqT3V3enBHYVJoR044QjRqT1B6aHVDT0V0ZDM3UzAybHUwN09IenlCdmJzVEd6S3dCZ0x5bVdmR2tINEIKajdDTHNwOEZ6TkhLWnVhQmdwblo5SjZETE9Od2ZXZTJBWXA3TGRmT0tWQlVkTVhRaU9tN2pKOUhob0Ntdk1ONwpic2pjaFdKb013ckZmK3dkQUthdHowcUFQeWhMeWUvRnFtaVZ4a09SWmF3K1Q5bURaK0g0OXVBU2d1SnVOTXlRClY2RXlYNmd0Z1dxMzc2SHZhWE1TLzNoYW1Zb1ZXWEk1TXhpUE9ZeG5BQmtKQjRTQ2dJUmVqYkpmVmFRdG9RNGEKejAyaVVMZW5ESUllUU9Zb2JLY01CWGYxQjRQQVFtc2VocVZJYnpzUUNHaTU0VkRyczZiWmQvN0pzMXpDcHBncwpKaUQ1SXFNaktXRHdxN2FLCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
alpnProtocols:
- h3
certificates:
- name: envoy-gateway-tls-secret-1
privateKey: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
serverCertificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNxRENDQVpBQ0NRREVNZ1lZblFyQ29EQU5CZ2txaGtpRzl3MEJBUXNGQURBV01SUXdFZ1lEVlFRRERBdG0KYjI4dVltRnlMbU52YlRBZUZ3MHlNekF4TURVeE16UXpNalJhRncweU5EQXhNRFV4TXpRek1qUmFNQll4RkRBUwpCZ05WQkFNTUMyWnZieTVpWVhJdVkyOXRNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDCkFRRUFuZEh6d21wS2NUSUViamhGZ2RXd1RSTjc1Y3A4b3VsWnhMMUdydlI2SXc3ejdqaTBSNFcvTm85bkdmOU0KWVAyQ1JqaXN6NTFtd3hTeGVCcm9jTGVBK21reGkxK2lEdk5kQytyU0x4MTN6RUxTQ25xYnVzUHM3bUdmSlpxOAo5TGhlbmx5bzQzaDVjYTZINUxqTXd1L1JHVWlGMzFYck5yaVlGQlB2RTJyQitkd24vTkVrUTRoOFJxcXlwcmtuCkYvcWM5Sk1ZQVlGRld1VkNwa0lFbmRYMUN5dlFOT2FkZmN2cmd6dDV2SmwwT2kxQWdyaU5hWGJFUEdudWY3STQKcXBCSEdVWE5lMVdsOVdlVklxS1g0T2FFWERWQzZGQzdHOHptZWVMVzFBa1lFVm5pcFg2b1NCK0JjL1NIVlZOaApzQkxSbXRuc3pmTnRUMlFyZCttcGt4ODBaUUlEQVFBQk1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ1VKOElDCkJveUVqT3V3enBHYVJoR044QjRqT1B6aHVDT0V0ZDM3UzAybHUwN09IenlCdmJzVEd6S3dCZ0x5bVdmR2tINEIKajdDTHNwOEZ6TkhLWnVhQmdwblo5SjZETE9Od2ZXZTJBWXA3TGRmT0tWQlVkTVhRaU9tN2pKOUhob0Ntdk1ONwpic2pjaFdKb013ckZmK3dkQUthdHowcUFQeWhMeWUvRnFtaVZ4a09SWmF3K1Q5bURaK0g0OXVBU2d1SnVOTXlRClY2RXlYNmd0Z1dxMzc2SHZhWE1TLzNoYW1Zb1ZXWEk1TXhpUE9ZeG5BQmtKQjRTQ2dJUmVqYkpmVmFRdG9RNGEKejAyaVVMZW5ESUllUU9Zb2JLY01CWGYxQjRQQVFtc2VocVZJYnpzUUNHaTU0VkRyczZiWmQvN0pzMXpDcHBncwpKaUQ1SXFNaktXRHdxN2FLCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
maxVersion: "1.3"
minVersion: "1.2"
Empty file.
Empty file.
Empty file.
Loading
Loading