pkg/k8s: enable peers to use DNS names

This commit enables peers defined using the Peer CRD to declare their
endpoints using DNS names.

Signed-off-by: Lucas Servén Marín <lserven@gmail.com>
This commit is contained in:
Lucas Servén Marín 2020-02-28 15:48:32 +01:00
parent e3cb7d7958
commit 116fb7337a
No known key found for this signature in database
GPG Key ID: 586FEAF680DA74AD
6 changed files with 102 additions and 15 deletions

View File

@ -289,9 +289,16 @@ func translatePeer(peer *wireguard.Peer) *v1alpha1.Peer {
aips = append(aips, aip.String())
}
var endpoint *v1alpha1.PeerEndpoint
if peer.Endpoint != nil && peer.Endpoint.Port > 0 && peer.Endpoint.IP != nil {
if peer.Endpoint != nil && peer.Endpoint.Port > 0 && (peer.Endpoint.IP != nil || peer.Endpoint.DNS != "") {
var ip string
if peer.Endpoint.IP != nil {
ip = peer.Endpoint.IP.String()
}
endpoint = &v1alpha1.PeerEndpoint{
IP: peer.Endpoint.IP.String(),
DNSOrIP: v1alpha1.DNSOrIP{
DNS: peer.Endpoint.DNS,
IP: ip,
},
Port: peer.Endpoint.Port,
}
}

View File

@ -19,9 +19,11 @@ import (
"errors"
"fmt"
"net"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation"
)
const (
@ -81,12 +83,22 @@ type PeerSpec struct {
// PeerEndpoint represents a WireGuard enpoint, which is a ip:port tuple.
type PeerEndpoint struct {
// IP must be a valid IP address.
IP string `json:"ip"`
DNSOrIP
// Port must be a valid port number.
Port uint32 `json:"port"`
}
// DNSOrIP represents either a DNS name or an IP address.
// IPs, as they are more specific, are preferred.
type DNSOrIP struct {
// DNS must be a valid RFC 1123 subdomain.
// +optional
DNS string `json:"dns,omitempty"`
// IP must be a valid IP address.
// +optional
IP string `json:"ip,omitempty"`
}
// PeerName is the peer resource's FQDN.
var PeerName = PeerPlural + "." + GroupName
@ -127,10 +139,18 @@ func (p *Peer) Validate() error {
}
}
if p.Spec.Endpoint != nil {
if net.ParseIP(p.Spec.Endpoint.IP) == nil {
if p.Spec.Endpoint.IP == "" && p.Spec.Endpoint.DNS == "" {
return errors.New("either an endpoint DNS name IP address must be given")
}
if p.Spec.Endpoint.DNS != "" {
if errs := validation.IsDNS1123Subdomain(p.Spec.Endpoint.DNS); len(errs) != 0 {
return errors.New(strings.Join(errs, "; "))
}
}
if p.Spec.Endpoint.IP != "" && net.ParseIP(p.Spec.Endpoint.IP) == nil {
return fmt.Errorf("failed to parse %q as a valid IP address", p.Spec.Endpoint.IP)
}
if p.Spec.Endpoint.Port == 0 {
if 1 > p.Spec.Endpoint.Port || p.Spec.Endpoint.Port > 65535 {
return fmt.Errorf("port must be a valid UDP port number, got %d", p.Spec.Endpoint.Port)
}
}

View File

@ -22,6 +22,22 @@ import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DNSOrIP) DeepCopyInto(out *DNSOrIP) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSOrIP.
func (in *DNSOrIP) DeepCopy() *DNSOrIP {
if in == nil {
return nil
}
out := new(DNSOrIP)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Peer) DeepCopyInto(out *Peer) {
*out = *in
@ -52,6 +68,7 @@ func (in *Peer) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PeerEndpoint) DeepCopyInto(out *PeerEndpoint) {
*out = *in
out.DNSOrIP = in.DNSOrIP
return
}

View File

@ -325,10 +325,13 @@ func translatePeer(peer *v1alpha1.Peer) *mesh.Peer {
} else {
ip = ip.To16()
}
if peer.Spec.Endpoint.Port > 0 && ip != nil {
if peer.Spec.Endpoint.Port > 0 && (ip != nil || peer.Spec.Endpoint.DNS != "") {
endpoint = &wireguard.Endpoint{
DNSOrIP: wireguard.DNSOrIP{IP: ip},
Port: peer.Spec.Endpoint.Port,
DNSOrIP: wireguard.DNSOrIP{
DNS: peer.Spec.Endpoint.DNS,
IP: ip,
},
Port: peer.Spec.Endpoint.Port,
}
}
}
@ -464,8 +467,15 @@ func (pb *peerBackend) Set(name string, peer *mesh.Peer) error {
p.Spec.AllowedIPs[i] = peer.AllowedIPs[i].String()
}
if peer.Endpoint != nil {
var ip string
if peer.Endpoint.IP != nil {
ip = peer.Endpoint.IP.String()
}
p.Spec.Endpoint = &v1alpha1.PeerEndpoint{
IP: peer.Endpoint.IP.String(),
DNSOrIP: v1alpha1.DNSOrIP{
IP: ip,
DNS: peer.Endpoint.DNS,
},
Port: peer.Endpoint.Port,
}
}

View File

@ -240,17 +240,30 @@ func TestTranslatePeer(t *testing.T) {
name: "invalid endpoint ip",
spec: v1alpha1.PeerSpec{
Endpoint: &v1alpha1.PeerEndpoint{
IP: "foo",
DNSOrIP: v1alpha1.DNSOrIP{
IP: "foo",
},
Port: mesh.DefaultKiloPort,
},
},
out: &mesh.Peer{},
},
{
name: "valid endpoint",
name: "only endpoint port",
spec: v1alpha1.PeerSpec{
Endpoint: &v1alpha1.PeerEndpoint{
IP: "10.0.0.1",
Port: mesh.DefaultKiloPort,
},
},
out: &mesh.Peer{},
},
{
name: "valid endpoint ip",
spec: v1alpha1.PeerSpec{
Endpoint: &v1alpha1.PeerEndpoint{
DNSOrIP: v1alpha1.DNSOrIP{
IP: "10.0.0.1",
},
Port: mesh.DefaultKiloPort,
},
},
@ -263,6 +276,25 @@ func TestTranslatePeer(t *testing.T) {
},
},
},
{
name: "valid endpoint DNS",
spec: v1alpha1.PeerSpec{
Endpoint: &v1alpha1.PeerEndpoint{
DNSOrIP: v1alpha1.DNSOrIP{
DNS: "example.com",
},
Port: mesh.DefaultKiloPort,
},
},
out: &mesh.Peer{
Peer: wireguard.Peer{
Endpoint: &wireguard.Endpoint{
DNSOrIP: wireguard.DNSOrIP{DNS: "example.com"},
Port: mesh.DefaultKiloPort,
},
},
},
},
{
name: "empty key",
spec: v1alpha1.PeerSpec{

View File

@ -19,11 +19,12 @@ import (
"net"
"sort"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
"github.com/squat/kilo/pkg/encapsulation"
"github.com/squat/kilo/pkg/iptables"
"github.com/squat/kilo/pkg/wireguard"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
)
const kiloTableIndex = 1107