Skip to content

Commit

Permalink
Wireguard Tunnel Container
Browse files Browse the repository at this point in the history
  • Loading branch information
cheina97 committed Oct 18, 2023
1 parent dee6d96 commit 431a630
Show file tree
Hide file tree
Showing 21 changed files with 1,147 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ updates:
directory: "/build/proxy"
schedule:
interval: "daily"

- package-ecosystem: "docker"
directory: "/build/gateway/tunnel/wireguard"
schedule:
interval: "daily"
2 changes: 1 addition & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ jobs:
- metric-agent
- telemetry
- proxy
- gateway/wireguard
steps:

- name: Set up QEMU
uses: docker/[email protected]
with:
Expand Down
20 changes: 20 additions & 0 deletions build/gateway/wireguard/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM golang:1.21 as goBuilder
WORKDIR /tmp/builder

COPY go.mod ./go.mod
COPY go.sum ./go.sum
RUN go mod download

COPY . ./
RUN CGO_ENABLED=0 GOOS=linux GOARCH=$(go env GOARCH) go build -ldflags="-s -w" ./cmd/gateway/wireguard


FROM alpine:3.18

RUN apk update && \
apk add iptables bash wireguard-tools tcpdump conntrack-tools curl iputils && \
rm -rf /var/cache/apk/*

COPY --from=goBuilder /tmp/builder/wireguard /usr/bin/liqo-wireguard

ENTRYPOINT [ "/usr/bin/liqo-wireguard" ]
164 changes: 164 additions & 0 deletions cmd/gateway/wireguard/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright 2019-2023 The Liqo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package wireguard contains the logic to configure the Wireguard interface.
package main

import (
"flag"
"fmt"
"net"
"os"

"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/leaderelection/resourcelock"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log"

ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1"
"github.com/liqotech/liqo/pkg/gateway/tunnel/common"
"github.com/liqotech/liqo/pkg/gateway/tunnel/wireguard"
flagsutils "github.com/liqotech/liqo/pkg/utils/flags"
"github.com/liqotech/liqo/pkg/utils/mapper"
"github.com/liqotech/liqo/pkg/utils/restcfg"
)

var (
addToSchemeFunctions = []func(*runtime.Scheme) error{
corev1.AddToScheme,
networkingv1alpha1.AddToScheme,
ipamv1alpha1.AddToScheme,
}
options = wireguard.NewOptions()
)

func main() {
var cmd = cobra.Command{
Use: "liqo-wireguard",
RunE: run,
}

legacyflags := flag.NewFlagSet("legacy", flag.ExitOnError)
restcfg.InitFlags(legacyflags)
klog.InitFlags(legacyflags)
flagsutils.FromFlagToPflag(legacyflags, cmd.Flags())

wireguard.InitFlags(cmd.Flags(), options)
if err := wireguard.MarkFlagsRequired(&cmd, options); err != nil {
klog.Error(err)
os.Exit(1)
}

if err := cmd.Execute(); err != nil {
klog.Error(err)
os.Exit(1)
}
}

func run(cmd *cobra.Command, _ []string) error {
var err error
scheme := runtime.NewScheme()

// Adds the APIs to the scheme.
for _, addToScheme := range addToSchemeFunctions {
if err = addToScheme(scheme); err != nil {
return fmt.Errorf("unable to add scheme: %w", err)
}
}

// Set controller-runtime logger.
log.SetLogger(klog.NewKlogr())

// Get the rest config.
cfg := config.GetConfigOrDie()

// Create the client. This client should be used only outside the reconciler.
// This client don't need a cache.
cl, err := client.New(cfg, client.Options{
Scheme: scheme,
})
if err != nil {
return fmt.Errorf("unable to create client: %w", err)
}

// Create the manager.
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
MapperProvider: mapper.LiqoMapperProvider(scheme),
Scheme: scheme,
Namespace: options.Namespace,
MetricsBindAddress: options.MetricsAddress,
HealthProbeBindAddress: options.ProbeAddr,
LeaderElection: options.LeaderElection,
LeaderElectionID: fmt.Sprintf(
"%s.%s.%s.wgtunnel.liqo.io",
wireguard.GenerateResourceName(options.Name), options.Namespace, options.Mode,
),
LeaderElectionNamespace: options.Namespace,
LeaderElectionReleaseOnCancel: true,
LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
LeaseDuration: &options.LeaderElectionLeaseDuration,
RenewDeadline: &options.LeaderElectionRenewDeadline,
RetryPeriod: &options.LeaderElectionRetryPeriod,
})
if err != nil {
return fmt.Errorf("unable to create manager: %w", err)
}

// Setup the controller.
pkr, err := wireguard.NewPublicKeysReconciler(
mgr.GetClient(),
mgr.GetScheme(),
mgr.GetEventRecorderFor("public-keys-controller"),
options,
)
if err != nil {
return fmt.Errorf("unable to create public keys reconciler: %w", err)
}

dnsChan := make(chan event.GenericEvent)
if options.Mode == common.ModeClient {
if wireguard.IsDNSRoutineRequired(options) {
go wireguard.StartDNSRoutine(cmd.Context(), dnsChan, options)
klog.Infof("Starting DNS routine: resolving the endpoint address every %s", options.DNSCheckInterval.String())
} else {
options.EndpointIP = net.ParseIP(options.EndpointAddress)
klog.Infof("Setting static endpoint IP: %s", options.EndpointIP.String())
}
}

// Setup the controller.
if err = pkr.SetupWithManager(mgr, dnsChan); err != nil {
return fmt.Errorf("unable to setup public keys reconciler: %w", err)
}

// Ensure presence of Secret with private and public keys.
if err = wireguard.EnsureKeysSecret(cmd.Context(), cl, options); err != nil {
return fmt.Errorf("unable to manage wireguard keys secret: %w", err)
}

// Create the wg-liqo interface and init the wireguard configuration depending on the mode (client/server).
if err := wireguard.InitWireguardLink(options); err != nil {
return fmt.Errorf("unable to init wireguard link: %w", err)
}

// Start the manager.
return mgr.Start(cmd.Context())
}
2 changes: 2 additions & 0 deletions pkg/consts/externalnetwork.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ const (
// GatewayTypeClient indicates a Gateway of type client.
GatewayTypeClient = "client"

// PrivateKeyField is the data field of the secrets containing private keys.
PrivateKeyField = "privateKey"
// PublicKeyField is the data field of the secrets containing public keys.
PublicKeyField = "publicKey"
)
16 changes: 16 additions & 0 deletions pkg/gateway/tunnel/common/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2019-2023 The Liqo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package common contains the common functions used by the tunneling package.
package common
32 changes: 32 additions & 0 deletions pkg/gateway/tunnel/common/netlink.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2019-2023 The Liqo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package common

import "github.com/vishvananda/netlink"

// AddAddress adds an IP address to the Wireguard interface.
func AddAddress(link netlink.Link, ip string) error {
addr, err := netlink.ParseAddr(ip)
if err != nil {
return err
}

return netlink.AddrAdd(link, addr)
}

// GetLink returns the Wireguard interface.
func GetLink(name string) (netlink.Link, error) {
return netlink.LinkByName(name)
}
51 changes: 51 additions & 0 deletions pkg/gateway/tunnel/common/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2019-2023 The Liqo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package common

import (
"fmt"
)

// Mode is the mode in which the wireguard interface is configured.
type Mode string

const (
// ModeServer is the mode in which the wireguard interface is configured as a server.
ModeServer Mode = "server"
// ModeClient is the mode in which the wireguard interface is configured as a client.
ModeClient Mode = "client"
)

// String returns the string representation of the mode.
func (m Mode) String() string {
return string(m)
}

// Set sets the value of the mode.
func (m *Mode) Set(value string) error {
if value == "" {
return fmt.Errorf("mode cannot be empty")
}
if value != ModeServer.String() && value != ModeClient.String() {
return fmt.Errorf("invalid mode %q", value)
}
*m = Mode(value)
return nil
}

// Type returns the type of the mode.
func (m *Mode) Type() string {
return "string"
}
50 changes: 50 additions & 0 deletions pkg/gateway/tunnel/wireguard/device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2019-2023 The Liqo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package wireguard

import (
"net"

"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"

"github.com/liqotech/liqo/pkg/gateway/tunnel/common"
)

func configureDevice(wgcl *wgctrl.Client, options *Options, peerPubKey wgtypes.Key) error {
confdev := wgtypes.Config{
PrivateKey: &options.PrivateKey,
ListenPort: nil,
Peers: []wgtypes.PeerConfig{
{
PublicKey: peerPubKey,
AllowedIPs: []net.IPNet{{IP: net.IP{0, 0, 0, 0}, Mask: net.CIDRMask(0, 32)}},
},
},
ReplacePeers: true,
}

switch options.Mode {
case common.ModeServer:
confdev.ListenPort = &options.ListenPort
case common.ModeClient:
confdev.Peers[0].Endpoint = &net.UDPAddr{
IP: options.EndpointIP,
Port: options.EndpointPort,
}
}

return wgcl.ConfigureDevice(options.InterfaceName, confdev)
}
Loading

0 comments on commit 431a630

Please sign in to comment.