Skip to content
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ See [SECURITY.md](docs/SECURITY.md) for complete security specifications and imp
- **Operating System**: Currently supports Ubuntu 22 only
- **Architecture**: Designed for GPU-accelerated compute workloads
- **Access Method**: Requires SSH server and SSH key-based authentication
- **System Requirements**: Requires systemd to be running and accessible

---

Expand Down
3 changes: 2 additions & 1 deletion docs/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This document outlines the security requirements and best practices for implemen
**Implementation Requirements:**

- SSH server (OpenSSH or equivalent) must be installed and running on all instances
- systemd must be running and accessible via systemctl command
- SSH key pairs must be supported for authentication
- Public keys must be injectable during instance provisioning
- SSH access must be available through the configured firewall rules
Expand Down Expand Up @@ -136,4 +137,4 @@ For security issues, vulnerabilities, or questions:

---

**Note**: This document is a living document and will be updated as security requirements evolve. All cloud integrations must comply with these requirements to ensure the security and integrity of the Brev Compute SDK ecosystem.
**Note**: This document is a living document and will be updated as security requirements evolve. All cloud integrations must comply with these requirements to ensure the security and integrity of the Brev Compute SDK ecosystem.
119 changes: 80 additions & 39 deletions pkg/v1/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,84 +30,125 @@ type Image struct {
}

func ValidateInstanceImage(ctx context.Context, instance Instance, privateKey string) error {
// First ensure the instance is running and SSH accessible
sshUser := instance.SSHUser
sshPort := instance.SSHPort
publicIP := instance.PublicIP
sshClient, err := connectToInstance(ctx, instance, privateKey)
if err != nil {
return err
}
defer func() {
if closeErr := sshClient.Close(); closeErr != nil {
fmt.Printf("warning: failed to close SSH connection: %v\n", closeErr)
}
}()

arch, err := validateArchitecture(ctx, sshClient)
if err != nil {
return err
}

osVersion, err := validateOSVersion(ctx, sshClient)
if err != nil {
return err
}

homeDir, err := validateHomeDirectory(ctx, sshClient, instance.SSHUser)
if err != nil {
return err
}

systemdStatus, err := validateSystemd(ctx, sshClient)
if err != nil {
return err
}

// Validate that we have the required SSH connection details
if sshUser == "" {
return fmt.Errorf("SSH user is not set for instance %s", instance.CloudID)
fmt.Printf("Instance image validation passed for %s: architecture=%s, os=%s, home=%s, systemd=%s\n",
instance.CloudID, arch, osVersion, homeDir, systemdStatus)

return nil
}

func connectToInstance(ctx context.Context, instance Instance, privateKey string) (*ssh.Client, error) {
if instance.SSHUser == "" {
return nil, fmt.Errorf("SSH user is not set for instance %s", instance.CloudID)
}
if sshPort == 0 {
return fmt.Errorf("SSH port is not set for instance %s", instance.CloudID)
if instance.SSHPort == 0 {
return nil, fmt.Errorf("SSH port is not set for instance %s", instance.CloudID)
}
if publicIP == "" {
return fmt.Errorf("public IP is not available for instance %s", instance.CloudID)
if instance.PublicIP == "" {
return nil, fmt.Errorf("public IP is not available for instance %s", instance.CloudID)
}

// Connect to the instance via SSH
sshClient, err := ssh.ConnectToHost(ctx, ssh.ConnectionConfig{
User: sshUser,
HostPort: fmt.Sprintf("%s:%d", publicIP, sshPort),
User: instance.SSHUser,
HostPort: fmt.Sprintf("%s:%d", instance.PublicIP, instance.SSHPort),
PrivKey: privateKey,
})
if err != nil {
return fmt.Errorf("failed to connect to instance via SSH: %w", err)
return nil, fmt.Errorf("failed to connect to instance via SSH: %w", err)
}
defer func() {
if closeErr := sshClient.Close(); closeErr != nil {
// Log close error but don't return it as it's not the primary error
fmt.Printf("warning: failed to close SSH connection: %v\n", closeErr)
}
}()
return sshClient, nil
}

// Check 1: Verify x86_64 architecture
func validateArchitecture(ctx context.Context, sshClient *ssh.Client) (string, error) {
stdout, stderr, err := sshClient.RunCommand(ctx, "uname -m")
if err != nil {
return fmt.Errorf("failed to check architecture: %w, stdout: %s, stderr: %s", err, stdout, stderr)
return "", fmt.Errorf("failed to check architecture: %w, stdout: %s, stderr: %s", err, stdout, stderr)
}
if !strings.Contains(strings.TrimSpace(stdout), "x86_64") {
return fmt.Errorf("expected x86_64 architecture, got: %s", strings.TrimSpace(stdout))
arch := strings.TrimSpace(stdout)
if !strings.Contains(arch, "x86_64") {
return "", fmt.Errorf("expected x86_64 architecture, got: %s", arch)
}
return "x86_64", nil
}

// Check 2: Verify Ubuntu 20.04 or 22.04
stdout, stderr, err = sshClient.RunCommand(ctx, "cat /etc/os-release | grep PRETTY_NAME")
func validateOSVersion(ctx context.Context, sshClient *ssh.Client) (string, error) {
stdout, stderr, err := sshClient.RunCommand(ctx, "cat /etc/os-release | grep PRETTY_NAME")
if err != nil {
return fmt.Errorf("failed to check OS version: %w, stdout: %s, stderr: %s", err, stdout, stderr)
return "", fmt.Errorf("failed to check OS version: %w, stdout: %s, stderr: %s", err, stdout, stderr)
}

parts := strings.Split(strings.TrimSpace(stdout), "=")
if len(parts) != 2 {
return fmt.Errorf("error: os pretty name not in format PRETTY_NAME=\"Ubuntu\": %s", stdout)
return "", fmt.Errorf("error: os pretty name not in format PRETTY_NAME=\"Ubuntu\": %s", stdout)
}

// Remove quotes from the value
osVersion := strings.Trim(parts[1], "\"")
ubuntuRegex := regexp.MustCompile(`Ubuntu 20\.04|22\.04`)
if !ubuntuRegex.MatchString(osVersion) {
return fmt.Errorf("expected Ubuntu 20.04 or 22.04, got: %s", osVersion)
return "", fmt.Errorf("expected Ubuntu 20.04 or 22.04, got: %s", osVersion)
}
return osVersion, nil
}

// Check 3: Verify home directory
stdout, stderr, err = sshClient.RunCommand(ctx, "cd ~ && pwd")
func validateHomeDirectory(ctx context.Context, sshClient *ssh.Client, sshUser string) (string, error) {
stdout, stderr, err := sshClient.RunCommand(ctx, "cd ~ && pwd")
if err != nil {
return fmt.Errorf("failed to check home directory: %w, stdout: %s, stderr: %s", err, stdout, stderr)
return "", fmt.Errorf("failed to check home directory: %w, stdout: %s, stderr: %s", err, stdout, stderr)
}

homeDir := strings.TrimSpace(stdout)
if sshUser == "ubuntu" {
if !strings.Contains(homeDir, "/home/ubuntu") {
return fmt.Errorf("expected ubuntu user home directory to contain /home/ubuntu, got: %s", homeDir)
return "", fmt.Errorf("expected ubuntu user home directory to contain /home/ubuntu, got: %s", homeDir)
}
} else {
if !strings.Contains(homeDir, "/root") {
return fmt.Errorf("expected non-ubuntu user home directory to contain /root, got: %s", homeDir)
return "", fmt.Errorf("expected non-ubuntu user home directory to contain /root, got: %s", homeDir)
}
}
return homeDir, nil
}

fmt.Printf("Instance image validation passed for %s: architecture=%s, os=%s, home=%s\n",
instance.CloudID, "x86_64", osVersion, homeDir)
func validateSystemd(ctx context.Context, sshClient *ssh.Client) (string, error) {
stdout, stderr, err := sshClient.RunCommand(ctx, "systemctl is-system-running")

return nil
systemdStatus := strings.TrimSpace(stdout)
if systemdStatus == "running" || systemdStatus == "degraded" {
return systemdStatus, nil
}

if err != nil {
return "", fmt.Errorf("failed to check systemd status: %w, stdout: %s, stderr: %s", err, stdout, stderr)
}

return "", fmt.Errorf("expected systemd to be running or degraded, got: %s", systemdStatus)
}
Loading