talos/internal/app/apid/pkg/director/local_address.go
Andrey Smirnov 2dadcd6695
fix: stop worker nodes from acting as apid routers
Don't allow worker nodes to act as apid routers:

* don't try to issue client certificate for apid on worker nodes
* if worker nodes receives incoming connections with `--nodes` set to
  one of the local addresses of the nodd, it routes the request to
  itself without proxying

Second point allows using `talosctl -e worker -n worker` to connect
directly to the worker if the connection from the control plane is not
available for some reason.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2022-09-13 15:07:31 +04:00

90 lines
2.3 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package director
import (
"context"
"sync"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/state"
"github.com/talos-systems/talos/pkg/machinery/resources/network"
)
// LocalAddressProvider provides local address information.
type LocalAddressProvider interface {
IsLocalTarget(string) bool
}
// localAddressProvider watches and keeps track of the local node addresses.
type localAddressProvider struct {
mu sync.Mutex
localAddresses map[string]struct{}
localHostnames map[string]struct{}
}
// NewLocalAddressProvider initializes and returns a new LocalAddressProvider.
func NewLocalAddressProvider(st state.State) (*localAddressProvider, error) {
p := &localAddressProvider{}
evCh := make(chan state.Event)
if err := st.Watch(context.Background(), resource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.NodeAddressCurrentID, resource.VersionUndefined), evCh); err != nil {
return nil, err
}
if err := st.Watch(context.Background(), resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined), evCh); err != nil {
return nil, err
}
go p.watch(evCh)
return p, nil
}
func (p *localAddressProvider) watch(evCh <-chan state.Event) {
for ev := range evCh {
if ev.Type == state.Destroyed {
// shouldn't happen
continue
}
switch r := ev.Resource.(type) {
case *network.NodeAddress:
p.mu.Lock()
p.localAddresses = make(map[string]struct{}, len(r.TypedSpec().Addresses))
for _, addr := range r.TypedSpec().Addresses {
p.localAddresses[addr.Addr().String()] = struct{}{}
}
p.mu.Unlock()
case *network.HostnameStatus:
p.mu.Lock()
p.localHostnames = make(map[string]struct{}, 2)
p.localHostnames[r.TypedSpec().Hostname] = struct{}{}
p.localHostnames[r.TypedSpec().FQDN()] = struct{}{}
p.mu.Unlock()
}
}
}
// IsLocalTarget returns true if the address (hostname) is local.
func (p *localAddressProvider) IsLocalTarget(target string) bool {
p.mu.Lock()
defer p.mu.Unlock()
_, ok1 := p.localAddresses[target]
_, ok2 := p.localHostnames[target]
return ok1 || ok2
}