mirror of
https://github.com/netbirdio/netbird.git
synced 2025-06-02 08:06:01 +02:00
* wip: add posture checks structs * add netbird version check * Refactor posture checks and add version checks * Add posture check activities (#1445) * Integrate Endpoints for Posture Checks (#1432) * wip: add posture checks structs * add netbird version check * Refactor posture checks and add version checks * Implement posture and version checks in API models * Refactor API models and enhance posture check functionality * wip: add posture checks endpoints * go mod tidy * Reference the posture checks by id's in policy * Add posture checks management to server * Add posture checks management mocks * implement posture checks handlers * Add posture checks to account copy and fix tests * Refactor posture checks validation * wip: Add posture checks handler tests * Add JSON encoding support to posture checks * Encode posture checks to correct api response object * Refactored posture checks implementation to align with the new API schema * Refactor structure of `Checks` from slice to map * Cleanup * Add posture check activities (#1445) * Revert map to use list of checks * Add posture check activity events * Refactor posture check initialization in account test * Improve the handling of version range in posture check * Fix tests and linter * Remove max_version from NBVersionCheck * Added unit tests for NBVersionCheck * go mod tidy * Extend policy endpoint with posture checks (#1450) * Implement posture and version checks in API models * go mod tidy * Allow attaching posture checks to policy * Update error message for linked posture check on deleting * Refactor PostureCheck and Checks structures * go mod tidy * Add validation for non-existing posture checks * fix unit tests * use Wt version * Remove the enabled field, as posture check will now automatically be activated by default when attaching to a policy * wip: add posture checks structs * add netbird version check * Refactor posture checks and add version checks * Add posture check activities (#1445) * Integrate Endpoints for Posture Checks (#1432) * wip: add posture checks structs * add netbird version check * Refactor posture checks and add version checks * Implement posture and version checks in API models * Refactor API models and enhance posture check functionality * wip: add posture checks endpoints * go mod tidy * Reference the posture checks by id's in policy * Add posture checks management to server * Add posture checks management mocks * implement posture checks handlers * Add posture checks to account copy and fix tests * Refactor posture checks validation * wip: Add posture checks handler tests * Add JSON encoding support to posture checks * Encode posture checks to correct api response object * Refactored posture checks implementation to align with the new API schema * Refactor structure of `Checks` from slice to map * Cleanup * Add posture check activities (#1445) * Revert map to use list of checks * Add posture check activity events * Refactor posture check initialization in account test * Improve the handling of version range in posture check * Fix tests and linter * Remove max_version from NBVersionCheck * Added unit tests for NBVersionCheck * go mod tidy * Extend policy endpoint with posture checks (#1450) * Implement posture and version checks in API models * go mod tidy * Allow attaching posture checks to policy * Update error message for linked posture check on deleting * Refactor PostureCheck and Checks structures * go mod tidy * Add validation for non-existing posture checks * fix unit tests * use Wt version * Remove the enabled field, as posture check will now automatically be activated by default when attaching to a policy * Extend network map generation with posture checks (#1466) * Apply posture checks to network map generation * run policy posture checks on peers to connect * Refactor and streamline policy posture check process for peers to connect. * Add posture checks testing in a network map * Remove redundant nil check in policy.go * Refactor peer validation check in policy.go * Update 'Check' function signature and use logger for version check * Refactor posture checks run on sources and updated the validation func * Update peer validation * fix tests * improved test coverage for policy posture check * Refactoring * Extend NetBird agent to collect kernel version (#1495) * Add KernelVersion field to LoginRequest * Add KernelVersion to system info retrieval * Fix tests * Remove Core field from system info * Replace Core field with new OSVersion field in system info * Added WMI dependency to info_windows.go * Add OS Version posture checks (#1479) * Initial support of Geolocation service (#1491) * Add Geo Location posture check (#1500) * wip: implement geolocation check * add geo location posture checks to posture api * Merge branch 'feature/posture-checks' into geo-posture-check * Remove CityGeoNameID and update required fields in API * Add geoLocation checks to posture checks handler tests * Implement geo location-based checks for peers * Update test values and embed location struct in peer system * add support for country wide checks * initialize country code regex once * Fix peer meta core compability with older clients (#1515) * Refactor extraction of OSVersion in grpcserver * Ignore lint check * Fix peer meta core compability with older management (#1532) * Revert core field deprecation * fix tests * Extend peer meta with location information (#1517) This PR uses the geolocation service to resolve IP to location. The lookup happens once on the first connection - when a client calls the Sync func. The location is stored as part of the peer: * Add Locations endpoints (#1516) * add locations endpoints * Add sqlite3 check and database generation in geolite script * Add SQLite storage for geolocation data * Refactor file existence check into a separate function * Integrate geolocation services into management application * Refactoring * Refactor city retrieval to include Geonames ID * Add signature verification for GeoLite2 database download * Change to in-memory database for geolocation store * Merge manager to geolocation * Update GetAllCountries to return Country name and iso code * fix tests * Add reload to SqliteStore * Add geoname indexes * move db file check to connectDB * Add concurrency safety to SQL queries and database reloading The commit adds mutex locks to the GetAllCountries and GetCitiesByCountry functions to ensure thread-safety during database queries. Additionally, it introduces a mechanism to safely close the old database connection before a new connection is established upon reloading, which improves the reliability of database operations. Lastly, it moves the checking of database file existence to the connectDB function. * Add sha256 sum check to geolocation store before reload * Use read lock * Check SHA256 twice when reload geonames db --------- Co-authored-by: Yury Gargay <yury.gargay@gmail.com> * Add tests and validation for empty peer location in GeoLocationCheck (#1546) * Disallow Geo check creation/update without configured Geo DB (#1548) * Fix shared access to in memory copy of geonames.db (#1550) * Trim suffix in when evaluate Min Kernel Version in OS check * Add Valid Peer Windows Kernel version test * Add Geolocation handler tests (#1556) * Implement user admin checks in posture checks * Add geolocation handler tests * Mark initGeolocationTestData as helper func * Add error handling to geolocation database closure * Add cleanup function to close geolocation resources * Simplify checks definition serialisation (#1555) * Regenerate network map on posture check update (#1563) * change network state and generate map on posture check update * Refactoring * Make city name optional (#1575) * Do not return empty city name * Validate action param of geo location checks (#1577) We only support allow and deny * Switch realip middleware to upstream (#1578) * Be more silent in download-geolite2.sh script * Fix geonames db reload (#1580) * Ensure posture check name uniqueness when create (#1594) * Enhance the management of posture checks (#1595) * add a correct min version and kernel for os posture check example * handle error when geo or location db is nil * expose all peer location details in api response * Check for nil geolocation manager only * Validate posture check before save * bump open api version * add peer location fields to toPeerListItemResponse * Feautre/extend sys meta (#1536) * Collect network addresses * Add Linux sys product info * Fix peer meta comparison * Collect sys info on mac * Add windows sys info * Fix test * Fix test * Fix grpc client * Ignore test * Fix test * Collect IPv6 addresses * Change the IP to IP + net * fix tests * Use netip on server side * Serialize netip to json * Extend Peer metadata with cloud detection (#1552) * add cloud detection + test binary * test windows exe * Collect IPv6 addresses * Change the IP to IP + net * switch to forked cloud detect lib * new test builds * new GCE build * discontinue using library but local copy instead * fix imports * remove openstack check * add hierarchy to cloud check * merge IBM and SoftLayer * close resp bodies and use os lib for file reading * close more resp bodies * fix error check logic * parallelize IBM checks * fix response value * go mod tidy * include context + change kubernetes detection * add context in info functions * extract platform into separate field * fix imports * add missing wmi import --------- Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com> --------- Co-authored-by: pascal-fischer <32096965+pascal-fischer@users.noreply.github.com> * generate proto * remove test binaries --------- Co-authored-by: bcmmbaga <bethuelmbaga12@gmail.com> Co-authored-by: Yury Gargay <yury.gargay@gmail.com> Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com>
228 lines
7.0 KiB
Go
228 lines
7.0 KiB
Go
package peer
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"time"
|
|
)
|
|
|
|
// Peer represents a machine connected to the network.
|
|
// The Peer is a WireGuard peer identified by a public key
|
|
type Peer struct {
|
|
// ID is an internal ID of the peer
|
|
ID string `gorm:"primaryKey"`
|
|
// AccountID is a reference to Account that this object belongs
|
|
AccountID string `json:"-" gorm:"index;uniqueIndex:idx_peers_account_id_ip"`
|
|
// WireGuard public key
|
|
Key string `gorm:"index"`
|
|
// A setup key this peer was registered with
|
|
SetupKey string
|
|
// IP address of the Peer
|
|
IP net.IP `gorm:"uniqueIndex:idx_peers_account_id_ip"`
|
|
// Meta is a Peer system meta data
|
|
Meta PeerSystemMeta `gorm:"embedded;embeddedPrefix:meta_"`
|
|
// Name is peer's name (machine name)
|
|
Name string
|
|
// DNSLabel is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's
|
|
// domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
|
DNSLabel string
|
|
// Status peer's management connection status
|
|
Status *PeerStatus `gorm:"embedded;embeddedPrefix:peer_status_"`
|
|
// The user ID that registered the peer
|
|
UserID string
|
|
// SSHKey is a public SSH key of the peer
|
|
SSHKey string
|
|
// SSHEnabled indicates whether SSH server is enabled on the peer
|
|
SSHEnabled bool
|
|
// LoginExpirationEnabled indicates whether peer's login expiration is enabled and once expired the peer has to re-login.
|
|
// Works with LastLogin
|
|
LoginExpirationEnabled bool
|
|
// LastLogin the time when peer performed last login operation
|
|
LastLogin time.Time
|
|
// Indicate ephemeral peer attribute
|
|
Ephemeral bool
|
|
// Geo location based on connection IP
|
|
Location Location `gorm:"embedded;embeddedPrefix:location_"`
|
|
}
|
|
|
|
type PeerStatus struct {
|
|
// LastSeen is the last time peer was connected to the management service
|
|
LastSeen time.Time
|
|
// Connected indicates whether peer is connected to the management service or not
|
|
Connected bool
|
|
// LoginExpired
|
|
LoginExpired bool
|
|
// RequiresApproval indicates whether peer requires approval or not
|
|
RequiresApproval bool
|
|
}
|
|
|
|
// Location is a geo location information of a Peer based on public connection IP
|
|
type Location struct {
|
|
ConnectionIP net.IP // from grpc peer or reverse proxy headers depends on setup
|
|
CountryCode string
|
|
CityName string
|
|
GeoNameID uint // city level geoname id
|
|
}
|
|
|
|
// NetworkAddress is the IP address with network and MAC address of a network interface
|
|
type NetworkAddress struct {
|
|
NetIP netip.Prefix `gorm:"serializer:json"`
|
|
Mac string
|
|
}
|
|
|
|
// PeerSystemMeta is a metadata of a Peer machine system
|
|
type PeerSystemMeta struct {
|
|
Hostname string
|
|
GoOS string
|
|
Kernel string
|
|
Core string
|
|
Platform string
|
|
OS string
|
|
OSVersion string
|
|
WtVersion string
|
|
UIVersion string
|
|
KernelVersion string
|
|
NetworkAddresses []NetworkAddress `gorm:"serializer:json"`
|
|
SystemSerialNumber string
|
|
SystemProductName string
|
|
SystemManufacturer string
|
|
}
|
|
|
|
func (p PeerSystemMeta) isEqual(other PeerSystemMeta) bool {
|
|
if len(p.NetworkAddresses) != len(other.NetworkAddresses) {
|
|
return false
|
|
}
|
|
|
|
for _, addr := range p.NetworkAddresses {
|
|
var found bool
|
|
for _, oAddr := range other.NetworkAddresses {
|
|
if addr.Mac == oAddr.Mac && addr.NetIP == oAddr.NetIP {
|
|
found = true
|
|
continue
|
|
}
|
|
}
|
|
if !found {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return p.Hostname == other.Hostname &&
|
|
p.GoOS == other.GoOS &&
|
|
p.Kernel == other.Kernel &&
|
|
p.KernelVersion == other.KernelVersion &&
|
|
p.Core == other.Core &&
|
|
p.Platform == other.Platform &&
|
|
p.OS == other.OS &&
|
|
p.OSVersion == other.OSVersion &&
|
|
p.WtVersion == other.WtVersion &&
|
|
p.UIVersion == other.UIVersion &&
|
|
p.SystemSerialNumber == other.SystemSerialNumber &&
|
|
p.SystemProductName == other.SystemProductName &&
|
|
p.SystemManufacturer == other.SystemManufacturer
|
|
}
|
|
|
|
// AddedWithSSOLogin indicates whether this peer has been added with an SSO login by a user.
|
|
func (p *Peer) AddedWithSSOLogin() bool {
|
|
return p.UserID != ""
|
|
}
|
|
|
|
// Copy copies Peer object
|
|
func (p *Peer) Copy() *Peer {
|
|
peerStatus := p.Status
|
|
if peerStatus != nil {
|
|
peerStatus = p.Status.Copy()
|
|
}
|
|
return &Peer{
|
|
ID: p.ID,
|
|
AccountID: p.AccountID,
|
|
Key: p.Key,
|
|
SetupKey: p.SetupKey,
|
|
IP: p.IP,
|
|
Meta: p.Meta,
|
|
Name: p.Name,
|
|
DNSLabel: p.DNSLabel,
|
|
Status: peerStatus,
|
|
UserID: p.UserID,
|
|
SSHKey: p.SSHKey,
|
|
SSHEnabled: p.SSHEnabled,
|
|
LoginExpirationEnabled: p.LoginExpirationEnabled,
|
|
LastLogin: p.LastLogin,
|
|
Ephemeral: p.Ephemeral,
|
|
Location: p.Location,
|
|
}
|
|
}
|
|
|
|
// UpdateMetaIfNew updates peer's system metadata if new information is provided
|
|
// returns true if meta was updated, false otherwise
|
|
func (p *Peer) UpdateMetaIfNew(meta PeerSystemMeta) bool {
|
|
// Avoid overwriting UIVersion if the update was triggered sole by the CLI client
|
|
if meta.UIVersion == "" {
|
|
meta.UIVersion = p.Meta.UIVersion
|
|
}
|
|
|
|
if p.Meta.isEqual(meta) {
|
|
return false
|
|
}
|
|
p.Meta = meta
|
|
return true
|
|
}
|
|
|
|
// MarkLoginExpired marks peer's status expired or not
|
|
func (p *Peer) MarkLoginExpired(expired bool) {
|
|
newStatus := p.Status.Copy()
|
|
newStatus.LoginExpired = expired
|
|
if expired {
|
|
newStatus.Connected = false
|
|
}
|
|
p.Status = newStatus
|
|
}
|
|
|
|
// LoginExpired indicates whether the peer's login has expired or not.
|
|
// If Peer.LastLogin plus the expiresIn duration has happened already; then login has expired.
|
|
// Return true if a login has expired, false otherwise, and time left to expiration (negative when expired).
|
|
// Login expiration can be disabled/enabled on a Peer level via Peer.LoginExpirationEnabled property.
|
|
// Login expiration can also be disabled/enabled globally on the Account level via Settings.PeerLoginExpirationEnabled.
|
|
// Only peers added by interactive SSO login can be expired.
|
|
func (p *Peer) LoginExpired(expiresIn time.Duration) (bool, time.Duration) {
|
|
if !p.AddedWithSSOLogin() || !p.LoginExpirationEnabled {
|
|
return false, 0
|
|
}
|
|
expiresAt := p.LastLogin.Add(expiresIn)
|
|
now := time.Now()
|
|
timeLeft := expiresAt.Sub(now)
|
|
return timeLeft <= 0, timeLeft
|
|
}
|
|
|
|
// FQDN returns peers FQDN combined of the peer's DNS label and the system's DNS domain
|
|
func (p *Peer) FQDN(dnsDomain string) string {
|
|
if dnsDomain == "" {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("%s.%s", p.DNSLabel, dnsDomain)
|
|
}
|
|
|
|
// EventMeta returns activity event meta related to the peer
|
|
func (p *Peer) EventMeta(dnsDomain string) map[string]any {
|
|
return map[string]any{"name": p.Name, "fqdn": p.FQDN(dnsDomain), "ip": p.IP}
|
|
}
|
|
|
|
// Copy PeerStatus
|
|
func (p *PeerStatus) Copy() *PeerStatus {
|
|
return &PeerStatus{
|
|
LastSeen: p.LastSeen,
|
|
Connected: p.Connected,
|
|
LoginExpired: p.LoginExpired,
|
|
RequiresApproval: p.RequiresApproval,
|
|
}
|
|
}
|
|
|
|
// UpdateLastLogin and set login expired false
|
|
func (p *Peer) UpdateLastLogin() *Peer {
|
|
p.LastLogin = time.Now().UTC()
|
|
newStatus := p.Status.Copy()
|
|
newStatus.LoginExpired = false
|
|
p.Status = newStatus
|
|
return p
|
|
}
|