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

[vnet] install and run windows service #50468

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion lib/devicetrust/native/device_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ import (
"time"

"github.com/google/go-attestation/attest"
"github.com/gravitational/teleport"
"github.com/gravitational/trace"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sync/errgroup"
"golang.org/x/sys/windows"
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/gravitational/teleport"
devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1"
"github.com/gravitational/teleport/lib/windowsexec"
)
Expand Down
2 changes: 1 addition & 1 deletion lib/teleterm/vnet/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func (s *Service) Start(ctx context.Context, req *api.StartRequest) (*api.StartR
}

s.clusterConfigCache = vnet.NewClusterConfigCache(s.cfg.Clock)
processManager, err := vnet.Run(ctx, &vnet.RunConfig{
processManager, err := vnet.RunUserProcess(ctx, &vnet.UserProcessConfig{
AppProvider: appProvider,
ClusterConfigCache: s.clusterConfigCache,
})
Expand Down
61 changes: 9 additions & 52 deletions lib/vnet/admin_process.go → lib/vnet/admin_process_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ import (
"github.com/gravitational/teleport/lib/vnet/daemon"
)

type AdminProcessConfig daemon.Config

func (c *AdminProcessConfig) CheckAndSetDefaults() error {
return trace.Wrap((*daemon.Config)(c).CheckAndSetDefaults())
}

// RunAdminProcess must run as root. It creates and sets up a TUN device and passes
// the file descriptor for that device over the unix socket found at config.socketPath.
//
Expand All @@ -36,9 +42,9 @@ import (
//
// OS configuration is updated every [osConfigurationInterval]. During the update, it temporarily
// changes egid and euid of the process to that of the client connecting to the daemon.
func RunAdminProcess(ctx context.Context, config daemon.Config) error {
func RunAdminProcess(ctx context.Context, config AdminProcessConfig) error {
if err := config.CheckAndSetDefaults(); err != nil {
return trace.Wrap(err)
return trace.Wrap(err, "checking daemon process config")
}

ctx, cancel := context.WithCancel(ctx)
Expand All @@ -51,7 +57,7 @@ func RunAdminProcess(ctx context.Context, config daemon.Config) error {

errCh := make(chan error)
go func() {
errCh <- trace.Wrap(osConfigurationLoop(ctx, tunName, config.IPv6Prefix, config.DNSAddr, config.HomePath, config.ClientCred))
errCh <- trace.Wrap(osConfigurationLoop(ctx, tunName, config))
}()

// Stay alive until we get an error on errCh, indicating that the osConfig loop exited.
Expand Down Expand Up @@ -106,52 +112,3 @@ func createTUNDevice(ctx context.Context) (tun.Device, string, error) {
}
return dev, name, nil
}

// osConfigurationLoop will keep running until [ctx] is canceled or an unrecoverable error is encountered, in
// order to keep the host OS configuration up to date.
func osConfigurationLoop(ctx context.Context, tunName, ipv6Prefix, dnsAddr, homePath string, clientCred daemon.ClientCred) error {
osConfigurator, err := newOSConfigurator(tunName, ipv6Prefix, dnsAddr, homePath, clientCred)
if err != nil {
return trace.Wrap(err, "creating OS configurator")
}
defer func() {
if err := osConfigurator.close(); err != nil {
log.ErrorContext(ctx, "Error while closing OS configurator", "error", err)
}
}()

// Clean up any stale configuration left by a previous VNet instance that may have failed to clean up.
// This is necessary in case any stale /etc/resolver/<proxy address> entries are still present, we need to
// be able to reach the proxy in order to fetch the vnet_config.
if err := osConfigurator.deconfigureOS(ctx); err != nil {
return trace.Wrap(err, "cleaning up OS configuration on startup")
}

defer func() {
// Shutting down, deconfigure OS. Pass context.Background because [ctx] has likely been canceled
// already but we still need to clean up.
if err := osConfigurator.deconfigureOS(context.Background()); err != nil {
log.ErrorContext(ctx, "Error deconfiguring host OS before shutting down.", "error", err)
}
}()

if err := osConfigurator.updateOSConfiguration(ctx); err != nil {
return trace.Wrap(err, "applying initial OS configuration")
}

// Re-configure the host OS every 10 seconds. This will pick up any newly logged-in clusters by
// reading profiles from TELEPORT_HOME.
const osConfigurationInterval = 10 * time.Second
ticker := time.NewTicker(osConfigurationInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if err := osConfigurator.updateOSConfiguration(ctx); err != nil {
return trace.Wrap(err, "updating OS configuration")
}
case <-ctx.Done():
return ctx.Err()
}
}
}
100 changes: 100 additions & 0 deletions lib/vnet/admin_process_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Teleport
// Copyright (C) 2024 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package vnet

import (
"context"
"time"

"github.com/Microsoft/go-winio"
"github.com/gravitational/trace"
"golang.zx2c4.com/wireguard/tun"
)

type AdminProcessConfig struct {
// NamedPipe is the name of a pipe used for IPC between the user process and
// the admin service.
NamedPipe string

// TODO(nklaassen): delete these, the admin process will decide them, they
// don't need to be passed from the user process. Keeping them until I
// remove the references from osconfig.go.
IPv6Prefix string
DNSAddr string
HomePath string
}

func (c *AdminProcessConfig) CheckAndSetDefaults() error {
if c.NamedPipe == "" {
return trace.BadParameter("missing pipe path")
}
return nil
}

// RunAdminProcess must run as administrator. It creates and sets up a TUN
// device and runs the VNet networking stack.
//
// It also handles host OS configuration, OS configuration is updated every [osConfigurationInterval].
//
// The admin process will stay running until the socket at config.socketPath is
// deleted or until encountering an unrecoverable error.
func RunAdminProcess(ctx context.Context, cfg AdminProcessConfig) error {
if err := cfg.CheckAndSetDefaults(); err != nil {
return trace.Wrap(err, "checking admin process config")
}
log.InfoContext(ctx, "Running VNet admin process", "cfg", cfg)

dialTimeout := 200 * time.Millisecond
conn, err := winio.DialPipe(pipePath, &dialTimeout)
if err != nil {
return trace.Wrap(err, "dialing named pipe %s", pipePath)
}
conn.Close()
log.InfoContext(ctx, "Successfully connected to user process over named pipe", "pipe", pipePath)

device, err := tun.CreateTUN("TeleportVNet", mtu)
if err != nil {
return trace.Wrap(err, "creating TUN device")
}
defer device.Close()
tunName, err := device.Name()
if err != nil {
return trace.Wrap(err, "getting TUN device name")
}
log.InfoContext(ctx, "Created TUN interface", "tun", tunName)

// TODO(nklaassen): actually run VNet. For now, stay alive as long as we can
// dial the pipe.
for {
select {
case <-time.After(time.Second):
conn, err := winio.DialPipe(pipePath, &dialTimeout)
if err != nil {
return trace.Wrap(err, "failed to dial pipe, assuming user process has terminated")
}
conn.Close()
case <-ctx.Done():
return ctx.Err()
}
}
}

var (
// Satisfy unused linter.
// TODO(nklaassen): run os configuration loop in admin process.
_ = osConfigurationLoop
)
8 changes: 5 additions & 3 deletions lib/vnet/escalate_daemon_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ import (

// execAdminProcess is called from the normal user process to register and call
// the daemon process which runs as root.
func execAdminProcess(ctx context.Context, config daemon.Config) error {
return trace.Wrap(daemon.RegisterAndCall(ctx, config))
func execAdminProcess(ctx context.Context, config AdminProcessConfig) error {
return trace.Wrap(daemon.RegisterAndCall(ctx, daemon.Config(config)))
}

// DaemonSubcommand runs the VNet daemon process.
func DaemonSubcommand(ctx context.Context) error {
return trace.Wrap(daemon.Start(ctx, RunAdminProcess))
return trace.Wrap(daemon.Start(ctx, func(ctx context.Context, config daemon.Config) error {
return RunAdminProcess(ctx, AdminProcessConfig(config))
}))
}
3 changes: 1 addition & 2 deletions lib/vnet/escalate_nodaemon_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ import (

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/vnet/daemon"
)

// execAdminProcess is called from the normal user process to execute
// "tsh vnet-admin-setup" as root via an osascript wrapper.
func execAdminProcess(ctx context.Context, config daemon.Config) error {
func execAdminProcess(ctx context.Context, config AdminProcessConfig) error {
executableName, err := os.Executable()
if err != nil {
return trace.Wrap(err, "getting executable path")
Expand Down
Loading
Loading