Skip to content

Commit

Permalink
feat: include azure public IPs from standard LB SKU into extips
Browse files Browse the repository at this point in the history
Add public IP from Azure Standard SKU LB to the list of external IP (for
proper certificate generation).

Signed-off-by: Serge Logvinov <serge.logvinov@sinextra.dev>
Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
  • Loading branch information
sergelogvinov authored and smira committed May 27, 2022
1 parent 19edbb5 commit 458e44c
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 3 deletions.
65 changes: 62 additions & 3 deletions internal/app/machined/pkg/runtime/v1alpha1/platform/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"os"
"path/filepath"
"regexp"
"strings"

"github.com/talos-systems/go-procfs/procfs"
"golang.org/x/sys/unix"
Expand All @@ -34,7 +35,9 @@ const (
// AzureHostnameEndpoint is the local endpoint for the hostname.
AzureHostnameEndpoint = "http://169.254.169.254/metadata/instance/compute/osProfile/computerName?api-version=2021-12-13&format=text"
// AzureInterfacesEndpoint is the local endpoint to get external IPs.
AzureInterfacesEndpoint = "http://169.254.169.254/metadata/instance/network/interface?api-version=2021-12-13"
AzureInterfacesEndpoint = "http://169.254.169.254/metadata/instance/network/interface?api-version=2021-12-13&format=json"
// AzureLoadbalancerEndpoint is the local endpoint for load balancer config.
AzureLoadbalancerEndpoint = "http://169.254.169.254/metadata/loadbalancer?api-version=2021-05-01&format=json"

mnt = "/mnt"
)
Expand All @@ -55,6 +58,16 @@ type IPAddresses struct {
PublicIPAddress string `json:"publicIpAddress"`
}

// LoadBalancerMetadata represents load balancer metadata in IMDS.
type LoadBalancerMetadata struct {
LoadBalancer struct {
PublicIPAddresses []struct {
FrontendIPAddress string `json:"frontendIpAddress,omitempty"`
PrivateIPAddress string `json:"privateIpAddress,omitempty"`
} `json:"publicIpAddresses,omitempty"`
} `json:"loadbalancer,omitempty"`
}

// Azure is the concrete type that implements the platform.Platform interface.
type Azure struct{}

Expand Down Expand Up @@ -126,6 +139,25 @@ func (a *Azure) ParseMetadata(interfaceAddresses []NetworkConfig, host []byte) (
return &networkConfig, nil
}

// ParseLoadBalancerIP parses Azure LoadBalancer metadata into the platform external ip list.
func (a *Azure) ParseLoadBalancerIP(lbConfig LoadBalancerMetadata, exIP []netaddr.IP) ([]netaddr.IP, error) {
lbAddresses := exIP

for _, addr := range lbConfig.LoadBalancer.PublicIPAddresses {
ipaddr := addr.FrontendIPAddress

if i := strings.IndexByte(ipaddr, ']'); i != -1 {
ipaddr = strings.TrimPrefix(ipaddr[:i], "[")
}

if ip, err := netaddr.ParseIP(ipaddr); err == nil {
lbAddresses = append(lbAddresses, ip)
}
}

return lbAddresses, nil
}

// Configuration implements the platform.Platform interface.
func (a *Azure) Configuration(ctx context.Context) ([]byte, error) {
defer func() {
Expand Down Expand Up @@ -214,6 +246,8 @@ func (a *Azure) configFromCD() ([]byte, error) {
}

// NetworkConfiguration implements the runtime.Platform interface.
//
//nolint:gocyclo
func (a *Azure) NetworkConfiguration(ctx context.Context, ch chan<- *runtime.PlatformNetworkConfig) error {
log.Printf("fetching network config from %q", AzureInterfacesEndpoint)

Expand All @@ -236,12 +270,37 @@ func (a *Azure) NetworkConfiguration(ctx context.Context, ch chan<- *runtime.Pla
download.WithErrorOnNotFound(errors.ErrNoHostname),
download.WithErrorOnEmptyResponse(errors.ErrNoHostname))
if err != nil && !stderrors.Is(err, errors.ErrNoHostname) {
return err
return fmt.Errorf("failed to fetch hostname from metadata service: %w", err)
}

networkConfig, err := a.ParseMetadata(interfaceAddresses, host)
if err != nil {
return err
return fmt.Errorf("failed to parse network metadata: %w", err)
}

log.Printf("fetching load balancer metadata from: %q", AzureLoadbalancerEndpoint)

var loadBalancerAddresses LoadBalancerMetadata

lbConfig, err := download.Download(ctx, AzureLoadbalancerEndpoint,
download.WithHeaders(map[string]string{"Metadata": "true"}),
download.WithErrorOnNotFound(errors.ErrNoConfigSource),
download.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))
if err != nil && !stderrors.Is(err, errors.ErrNoConfigSource) {
log.Printf("failed to fetch load balancer config from metadata service: %s", err)

lbConfig = nil
}

if len(lbConfig) > 0 {
if err = json.Unmarshal(lbConfig, &loadBalancerAddresses); err != nil {
return fmt.Errorf("failed to parse loadbalancer metadata: %w", err)
}

networkConfig.ExternalIPs, err = a.ParseLoadBalancerIP(loadBalancerAddresses, networkConfig.ExternalIPs)
if err != nil {
return fmt.Errorf("failed to define externalIPs: %w", err)
}
}

select {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import (
//go:embed testdata/metadata.json
var rawMetadata []byte

//go:embed testdata/loadbalancer.json
var rawLoadBalancerMetadata []byte

//go:embed testdata/expected.yaml
var expectedNetworkConfig string

Expand All @@ -32,6 +35,13 @@ func TestParseMetadata(t *testing.T) {
networkConfig, err := a.ParseMetadata(m, []byte("some.fqdn"))
require.NoError(t, err)

var lb azure.LoadBalancerMetadata

require.NoError(t, json.Unmarshal(rawLoadBalancerMetadata, &lb))

networkConfig.ExternalIPs, err = a.ParseLoadBalancerIP(lb, networkConfig.ExternalIPs)
require.NoError(t, err)

marshaled, err := yaml.Marshal(networkConfig)
require.NoError(t, err)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ operators:
layer: default
externalIPs:
- 1.2.3.4
- 2603:1020:10:5::34
- 20.10.5.34
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"loadbalancer": {
"publicIpAddresses": [
{
"frontendIpAddress": "[2603:1020:10:5::34]",
"privateIpAddress": "[fd00::10]"
},
{
"frontendIpAddress": "20.10.5.34",
"privateIpAddress": "172.18.1.10"
}
],
"inboundRules": [
{
"frontendIpAddress": "[fd60:172:16:88::5]",
"protocol": "Tcp",
"frontendPort": 6443,
"backendPort": 6443,
"privateIpAddress": "[fd00::10]"
},
{
"frontendIpAddress": "172.16.136.5",
"protocol": "Tcp",
"frontendPort": 6443,
"backendPort": 6443,
"privateIpAddress": "172.18.1.10"
}
],
"outboundRules": []
}
}

0 comments on commit 458e44c

Please sign in to comment.