internal/metadata/exported.go (330 lines of code) (raw):
// Copyright 2024 Google LLC
//
// 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
//
// https://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 metadata
import (
"encoding/json"
"fmt"
"github.com/GoogleCloudPlatform/google-guest-agent/internal/utils/ssh"
)
// Descriptor wraps/holds all the metadata keys, the structure reflects the json
// descriptor returned with metadata call with alt=json. This is a read-only
// wrapper of the internal representation.
type Descriptor struct {
instance *Instance
project *Project
}
// Instance describes the metadata's instance attributes/keys. This is a
// read-only wrapper of the internal representation.
type Instance struct {
internal *instance
attributes *Attributes
networkInterfaces []*NetworkInterface
vlanInterfaces []map[int]*VlanInterface
virtualClock *VirtualClock
}
// VirtualClock describes the clock skew's configuration.
type VirtualClock struct {
internal *virtualClock
}
// NetworkInterface describes the instances network interfaces configurations.
// This is a read-only wrapper of the internal representation.
type NetworkInterface struct {
internal *networkInterface
}
// VlanInterface describes the instances vlan interface configurations.
// This is a read-only wrapper of the internal representation.
type VlanInterface struct {
internal *vlanInterface
}
// Project describes the projects instance's attributes. This is a read-only
// wrapper of the internal representation.
type Project struct {
internal *project
attributes *Attributes
}
// Attributes describes the project's attributes keys. This is a read-only
// wrapper of the internal representation.
type Attributes struct {
internal *attributes
windowsKeys []*WindowsKey
}
// WindowsKey describes the WindowsKey metadata keys. This is a read-only
// wrapper of the internal representation.
type WindowsKey struct {
internal *windowsKey
}
func newDescriptor(descriptor descriptor) *Descriptor {
return &Descriptor{
instance: newInstance(descriptor.Instance),
project: newProject(descriptor.Project),
}
}
// AccountManagerDisabled reports whether instance and project metadata
// indicates that windows accounts manager should be disabled.
func (desc *Descriptor) AccountManagerDisabled() bool {
if desc.Instance().Attributes().DisableAccountManager() != nil {
return *desc.Instance().Attributes().DisableAccountManager()
}
if desc.Project().Attributes().DisableAccountManager() != nil {
return *desc.Project().Attributes().DisableAccountManager()
}
return false
}
// OSLoginEnabled reports whether instance and project metadata attributes
// indicate that OSLogin should be enabled.
func (desc *Descriptor) OSLoginEnabled() bool {
var enable bool
if desc.Project().Attributes().EnableOSLogin() != nil {
enable = *desc.Project().Attributes().EnableOSLogin()
}
if desc.Instance().Attributes().EnableOSLogin() != nil {
enable = *desc.Instance().Attributes().EnableOSLogin()
}
return enable
}
// TwoFactorEnabled returns true if two factor authentication is enabled for
// OSLogin.
func (desc *Descriptor) TwoFactorEnabled() bool {
var enabled bool
// Check project level first allowing instance level to override.
if desc.Project().Attributes().TwoFactor() != nil {
enabled = *desc.Project().Attributes().TwoFactor()
}
// Instance level takes precedence over project level.
if desc.Instance().Attributes().TwoFactor() != nil {
enabled = *desc.Instance().Attributes().TwoFactor()
}
return enabled
}
// SecurityKeyEnabled returns true if security key is enabled for OSLogin.
func (desc *Descriptor) SecurityKeyEnabled() bool {
var enabled bool
// Check project level first allowing instance level to override.
if desc.Project().Attributes().SecurityKey() != nil {
enabled = *desc.Project().Attributes().SecurityKey()
}
// Instance level takes precedence over project level.
if desc.Instance().Attributes().SecurityKey() != nil {
enabled = *desc.Instance().Attributes().SecurityKey()
}
return enabled
}
// CertRequiredEnabled returns true if cert required is enabled for OSLogin.
func (desc *Descriptor) CertRequiredEnabled() bool {
var enabled bool
// Check project level first allowing instance level to override.
if desc.Project().Attributes().RequireCerts() != nil {
enabled = *desc.Project().Attributes().RequireCerts()
}
// Instance level takes precedence over project level.
if desc.Instance().Attributes().RequireCerts() != nil {
enabled = *desc.Instance().Attributes().RequireCerts()
}
return enabled
}
// WindowsSSHEnabled returns true if instance's or project's attributes has the
// enable-windows-ssh key is defined and set to true.
func (desc *Descriptor) WindowsSSHEnabled() bool {
instance := desc.Instance()
project := desc.Project()
// Instance's attribute takes precedence over projects.
if instance != nil && instance.Attributes().EnableWindowsSSH() != nil {
return bool(*instance.Attributes().EnableWindowsSSH())
}
// If the instance attribute doesn't enable it we can still have it enabled
// via projects attributes.
if project != nil && project.Attributes().EnableWindowsSSH() != nil {
return bool(*project.Attributes().EnableWindowsSSH())
}
return false
}
// UserSSHKeys returns the user's SSH keys.
func (desc *Descriptor) UserSSHKeys(username string) ([]string, error) {
var userKeys []string
if desc.Instance() == nil || desc.Project() == nil {
return userKeys, fmt.Errorf("USERSSHKeys() instance or project is nil")
}
instanceAttrs := desc.Instance().Attributes()
instanceKeyList := ssh.ParseKeys(username, instanceAttrs.SSHKeys())
userKeys = append(userKeys, instanceKeyList...)
if !instanceAttrs.BlockProjectKeys() {
projectAttrs := desc.Project().Attributes()
projectKeyList := ssh.ParseKeys(username, projectAttrs.SSHKeys())
userKeys = append(userKeys, projectKeyList...)
}
return userKeys, nil
}
// Instance returns the instance described by metadata server.
func (desc *Descriptor) Instance() *Instance {
return desc.instance
}
func newInstance(instance instance) *Instance {
res := &Instance{internal: &instance}
for _, nic := range instance.NetworkInterfaces {
res.networkInterfaces = append(res.networkInterfaces, newNetworkInterface(nic))
}
for _, vics := range instance.VlanInterfaces {
mp := make(map[int]*VlanInterface)
for vlanID, iface := range vics {
mp[vlanID] = newVlanInterface(iface)
}
res.vlanInterfaces = append(res.vlanInterfaces, mp)
}
res.attributes = newAttributes(instance.Attributes)
res.virtualClock = newVirtualClock(instance.VirtualClock)
return res
}
// ID returns the instance ID.
func (in *Instance) ID() json.Number {
return in.internal.ID
}
// Name returns the instance name.
func (in *Instance) Name() string {
return in.internal.Name
}
// MachineType returns the instance machine type.
func (in *Instance) MachineType() string {
return in.internal.MachineType
}
// Attributes returns the instance attributes.
func (in *Instance) Attributes() *Attributes {
return in.attributes
}
// NetworkInterfaces returns the instance network interfaces.
func (in *Instance) NetworkInterfaces() []*NetworkInterface {
return in.networkInterfaces
}
// VlanInterfaces returns the instance vlan interfaces.
func (in *Instance) VlanInterfaces() []map[int]*VlanInterface {
return in.vlanInterfaces
}
// VirtualClock returns the instance virtual clock.
func (in *Instance) VirtualClock() *VirtualClock {
return in.virtualClock
}
func newVirtualClock(vc virtualClock) *VirtualClock {
return &VirtualClock{internal: &vc}
}
// DriftToken returns the virtual clock drift token.
func (vc *VirtualClock) DriftToken() string {
return vc.internal.DriftToken
}
// Project returns the project described by metadata server.
func (desc *Descriptor) Project() *Project {
return desc.project
}
func newProject(project project) *Project {
return &Project{
internal: &project,
attributes: newAttributes(project.Attributes),
}
}
// Attributes returns the project attributes.
func (proj *Project) Attributes() *Attributes {
return proj.attributes
}
// ID returns the project ID.
func (proj *Project) ID() string {
return proj.internal.ID
}
// NumericProjectID returns the project ID.
func (proj *Project) NumericProjectID() json.Number {
return proj.internal.NumericProjectID
}
func newNetworkInterface(nic networkInterface) *NetworkInterface {
return &NetworkInterface{internal: &nic}
}
// ForwardedIPs returns the instance network interfaces forwarded IPs.
func (nic *NetworkInterface) ForwardedIPs() []string {
return nic.internal.ForwardedIps
}
// ForwardedIPv6s returns the instance network interfaces forwarded IPv6s.
func (nic *NetworkInterface) ForwardedIPv6s() []string {
return nic.internal.ForwardedIpv6s
}
// TargetInstanceIPs returns the instance network interfaces target instance
// IPs.
func (nic *NetworkInterface) TargetInstanceIPs() []string {
return nic.internal.TargetInstanceIps
}
// IPAliases returns the instance network interfaces IP aliases.
func (nic *NetworkInterface) IPAliases() []string {
return nic.internal.IPAliases
}
// MAC returns the instance network interfaces MAC address.
func (nic *NetworkInterface) MAC() string {
return nic.internal.Mac
}
// DHCPv6Refresh returns the instance network interfaces DHCPv6 refresh.
func (nic *NetworkInterface) DHCPv6Refresh() string {
return nic.internal.DHCPv6Refresh
}
func newVlanInterface(nic vlanInterface) *VlanInterface {
return &VlanInterface{internal: &nic}
}
// MAC returns the instance vlan interfaces MAC address.
func (vic *VlanInterface) MAC() string {
return vic.internal.Mac
}
// ParentInterface returns the instance vlan interfaces parent interface.
func (vic *VlanInterface) ParentInterface() string {
return vic.internal.ParentInterface
}
// Vlan returns the instance vlan interfaces vlan.
func (vic *VlanInterface) Vlan() int {
return vic.internal.Vlan
}
// MTU returns the instance vlan interfaces MTU.
func (vic *VlanInterface) MTU() int {
return vic.internal.MTU
}
// IPAddress returns the instance vlan interfaces IP address.
func (vic *VlanInterface) IPAddress() string {
return vic.internal.IP
}
// IPv6Addresses returns the instance vlan interfaces IPv6 addresses.
func (vic *VlanInterface) IPv6Addresses() []string {
return vic.internal.IPv6
}
// Gateway returns the instance vlan interfaces gateway.
func (vic *VlanInterface) Gateway() string {
return vic.internal.Gateway
}
// GatewayIPv6 returns the instance vlan interfaces gateway IPv6.
func (vic *VlanInterface) GatewayIPv6() string {
return vic.internal.GatewayIPv6
}
func newAttributes(attributes attributes) *Attributes {
res := &Attributes{internal: &attributes}
for _, windowsKey := range attributes.WindowsKeys {
res.windowsKeys = append(res.windowsKeys, &WindowsKey{internal: &windowsKey})
}
return res
}
// CreatedBy returns the attribute created-by.
func (attr *Attributes) CreatedBy() string {
return attr.internal.CreatedBy
}
// Hostname returns the attribute hostname.
func (attr *Attributes) Hostname() string {
return attr.internal.Hostname
}
// BlockProjectKeys returns the attributes block project keys.
func (attr *Attributes) BlockProjectKeys() bool {
return attr.internal.BlockProjectKeys
}
// EnableOSLogin returns the attributes enable OS login.
func (attr *Attributes) EnableOSLogin() *bool {
return attr.internal.EnableOSLogin
}
// EnableWindowsSSH returns the attributes enable windows ssh.
func (attr *Attributes) EnableWindowsSSH() *bool {
return attr.internal.EnableWindowsSSH
}
// TwoFactor returns the attributes two factor.
func (attr *Attributes) TwoFactor() *bool {
return attr.internal.TwoFactor
}
// SecurityKey returns the attributes security key.
func (attr *Attributes) SecurityKey() *bool {
return attr.internal.SecurityKey
}
// RequireCerts returns the attributes require certs.
func (attr *Attributes) RequireCerts() *bool {
return attr.internal.RequireCerts
}
// SSHKeys returns the attributes SSH keys.
func (attr *Attributes) SSHKeys() []string {
return attr.internal.SSHKeys
}
// WindowsKeys returns the attributes windows keys.
func (attr *Attributes) WindowsKeys() []*WindowsKey {
return attr.windowsKeys
}
// Diagnostics returns the attributes diagnostics.
func (attr *Attributes) Diagnostics() string {
return attr.internal.Diagnostics
}
// DisableAddressManager returns the attributes disable address
// manager.
func (attr *Attributes) DisableAddressManager() *bool {
return attr.internal.DisableAddressManager
}
// DisableAccountManager returns the attributes disable account
// manager.
func (attr *Attributes) DisableAccountManager() *bool {
return attr.internal.DisableAccountManager
}
// EnableDiagnostics returns the attributes enable diagnostics.
func (attr *Attributes) EnableDiagnostics() *bool {
return attr.internal.EnableDiagnostics
}
// EnableCorePlugin returns the attributes enable core plugin.
func (attr *Attributes) EnableCorePlugin() *bool {
return attr.internal.EnableCorePlugin
}
// EnableWSFC returns the attributes enable wsfc.
func (attr *Attributes) EnableWSFC() *bool {
return attr.internal.EnableWSFC
}
// WSFCAddresses returns the attributes wsfc addresses.
func (attr *Attributes) WSFCAddresses() string {
return attr.internal.WSFCAddresses
}
// WSFCAgentPort returns the attributes wsfc agent port.
func (attr *Attributes) WSFCAgentPort() string {
return attr.internal.WSFCAgentPort
}
// DisableTelemetry returns the attributes disable telemetry.
func (attr *Attributes) DisableTelemetry() bool {
return attr.internal.DisableTelemetry
}
// Email is the windows email key.
func (wk *WindowsKey) Email() string {
return wk.internal.Email
}
// ExpireOn is the windows expireOn key.
func (wk *WindowsKey) ExpireOn() string {
return wk.internal.ExpireOn
}
// Exponent is the windows exponent key.
func (wk *WindowsKey) Exponent() string {
return wk.internal.Exponent
}
// Modulus is the windows modulus key.
func (wk *WindowsKey) Modulus() string {
return wk.internal.Modulus
}
// UserName is the windows userName key.
func (wk *WindowsKey) UserName() string {
return wk.internal.UserName
}
// HashFunction is the windows hashFunction key.
func (wk *WindowsKey) HashFunction() string {
return wk.internal.HashFunction
}
// AddToAdministrator is the windows addToAdministrator key.
func (wk *WindowsKey) AddToAdministrator() *bool {
return wk.internal.AddToAdministrators
}
// PasswordLength is the windows passwordLength key.
func (wk *WindowsKey) PasswordLength() int {
return wk.internal.PasswordLength
}
// HasServiceAccount returns true if the instance has service accounts attached.
func (desc *Descriptor) HasServiceAccount() bool {
return len(desc.Instance().internal.ServiceAccounts) > 0
}
// HasCorePluginEnabled returns whether the Core Plugin is enabled or not based
// on MDS descriptor. If neither instance or project level metadata is set, it
// defaults to *false*.
func (desc *Descriptor) HasCorePluginEnabled() bool {
if desc.Instance().Attributes().EnableCorePlugin() != nil {
return *desc.Instance().Attributes().EnableCorePlugin()
}
if desc.Project().Attributes().EnableCorePlugin() != nil {
return *desc.Project().Attributes().EnableCorePlugin()
}
return false
}