Skip to content
Open
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
150 changes: 138 additions & 12 deletions packages/cmd/kmip.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@ package cmd

import (
"fmt"
"os"
"os/exec"
"runtime"

"github.com/Infisical/infisical-merge/packages/config"
localkmip "github.com/Infisical/infisical-merge/packages/kmip"
"github.com/Infisical/infisical-merge/packages/util"
kmip "github.com/infisical/infisical-kmip"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)

var kmipCmd = &cobra.Command{
Example: `infisical kmip`,
Example: ` infisical kmip
infisical kmip start --identity-client-id=<client-id> --identity-client-secret=<client-secret> --hostnames-or-ips=<hostnames-or-ips>
sudo infisical kmip systemd install --identity-client-id=<client-id> --identity-client-secret=<client-secret> --hostnames-or-ips=<hostnames-or-ips>`,
Short: "Used to manage KMIP servers",
Use: "kmip",
DisableFlagsInUseLine: true,
Expand All @@ -29,10 +36,17 @@ var kmipStartCmd = &cobra.Command{
Run: startKmipServer,
}

const (
INFISICAL_KMIP_LISTEN_ADDRESS_ENV_NAME = "INFISICAL_KMIP_LISTEN_ADDRESS"
INFISICAL_KMIP_SERVER_NAME_ENV_NAME = "INFISICAL_KMIP_SERVER_NAME"
INFISICAL_KMIP_CERTIFICATE_TTL_ENV_NAME = "INFISICAL_KMIP_CERTIFICATE_TTL"
INFISICAL_KMIP_HOSTNAMES_OR_IPS_ENV_NAME = "INFISICAL_KMIP_HOSTNAMES_OR_IPS"
)

func startKmipServer(cmd *cobra.Command, args []string) {
listenAddr, err := cmd.Flags().GetString("listen-address")
listenAddr, err := util.GetCmdFlagOrEnvWithDefaultValue(cmd, "listen-address", []string{INFISICAL_KMIP_LISTEN_ADDRESS_ENV_NAME}, "localhost:5696")
if err != nil {
util.HandleError(err, "Unable to parse flag")
util.HandleError(err, "Unable to parse listen address")
}

identityAuthMethod, err := cmd.Flags().GetString("identity-auth-method")
Expand All @@ -50,7 +64,6 @@ func startKmipServer(cmd *cobra.Command, args []string) {

if strategy == util.AuthStrategy.UNIVERSAL_AUTH {
identityClientId, err = util.GetCmdFlagOrEnv(cmd, "identity-client-id", []string{util.INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME})

if err != nil {
util.HandleError(err, "Unable to parse identity client ID")
}
Expand All @@ -63,19 +76,19 @@ func startKmipServer(cmd *cobra.Command, args []string) {
util.PrintErrorMessageAndExit(fmt.Sprintf("Unsupported login method: %s", identityAuthMethod))
}

serverName, err := cmd.Flags().GetString("server-name")
serverName, err := util.GetCmdFlagOrEnvWithDefaultValue(cmd, "server-name", []string{INFISICAL_KMIP_SERVER_NAME_ENV_NAME}, "kmip-server")
if err != nil {
util.HandleError(err, "Unable to parse flag")
util.HandleError(err, "Unable to parse server name")
}

certificateTTL, err := cmd.Flags().GetString("certificate-ttl")
certificateTTL, err := util.GetCmdFlagOrEnvWithDefaultValue(cmd, "certificate-ttl", []string{INFISICAL_KMIP_CERTIFICATE_TTL_ENV_NAME}, "1y")
if err != nil {
util.HandleError(err, "Unable to parse flag")
util.HandleError(err, "Unable to parse certificate TTL")
}

hostnamesOrIps, err := cmd.Flags().GetString("hostnames-or-ips")
hostnamesOrIps, err := util.GetCmdFlagOrEnv(cmd, "hostnames-or-ips", []string{INFISICAL_KMIP_HOSTNAMES_OR_IPS_ENV_NAME})
if err != nil {
util.HandleError(err, "Unable to parse flag")
util.HandleError(err, "Unable to parse hostnames or IPs")
}

kmip.StartServer(kmip.ServerConfig{
Expand All @@ -89,15 +102,128 @@ func startKmipServer(cmd *cobra.Command, args []string) {
})
}

var kmipSystemdCmd = &cobra.Command{
Use: "systemd",
Short: "Manage systemd service for Infisical KMIP server",
Long: "Manage systemd service for Infisical KMIP server. Use 'systemd install' to install and enable the service.",
Example: ` sudo infisical kmip systemd install --identity-client-id=<client-id> --identity-client-secret=<client-secret> --hostnames-or-ips=<hostnames-or-ips>
sudo infisical kmip systemd uninstall`,
DisableFlagsInUseLine: true,
Args: cobra.NoArgs,
}

var kmipSystemdInstallCmd = &cobra.Command{
Use: "install",
Short: "Install and enable systemd service for the KMIP server (requires sudo)",
Long: "Install and enable systemd service for the KMIP server. Must be run with sudo on Linux.",
Example: "sudo infisical kmip systemd install --identity-client-id=<client-id> --identity-client-secret=<client-secret> --hostnames-or-ips=<hostnames-or-ips>",
DisableFlagsInUseLine: true,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
if runtime.GOOS != "linux" {
util.HandleError(fmt.Errorf("systemd service installation is only supported on Linux"))
}

if os.Geteuid() != 0 {
util.HandleError(fmt.Errorf("systemd service installation requires root/sudo privileges"))
}

identityClientId, err := util.GetCmdFlagOrEnv(cmd, "identity-client-id", []string{util.INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME})
if err != nil {
util.HandleError(err, "Unable to parse identity client ID")
}

identityClientSecret, err := util.GetCmdFlagOrEnv(cmd, "identity-client-secret", []string{util.INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME})
if err != nil {
util.HandleError(err, "Unable to parse identity client secret")
}

domain, err := util.GetCmdFlagOrEnvWithDefaultValue(cmd, "domain", []string{util.INFISICAL_API_URL_ENV_NAME}, "")
if err != nil {
util.HandleError(err, "Unable to parse domain")
}

listenAddress, err := util.GetCmdFlagOrEnvWithDefaultValue(cmd, "listen-address", []string{INFISICAL_KMIP_LISTEN_ADDRESS_ENV_NAME}, "localhost:5696")
if err != nil {
util.HandleError(err, "Unable to parse listen address")
}

serverName, err := util.GetCmdFlagOrEnvWithDefaultValue(cmd, "server-name", []string{INFISICAL_KMIP_SERVER_NAME_ENV_NAME}, "kmip-server")
if err != nil {
util.HandleError(err, "Unable to parse server name")
}

certificateTTL, err := util.GetCmdFlagOrEnvWithDefaultValue(cmd, "certificate-ttl", []string{INFISICAL_KMIP_CERTIFICATE_TTL_ENV_NAME}, "1y")
if err != nil {
util.HandleError(err, "Unable to parse certificate TTL")
}

hostnamesOrIps, err := util.GetCmdFlagOrEnv(cmd, "hostnames-or-ips", []string{INFISICAL_KMIP_HOSTNAMES_OR_IPS_ENV_NAME})
if err != nil {
util.HandleError(err, "Unable to parse hostnames or IPs")
}

err = localkmip.InstallKmipSystemdService(identityClientId, identityClientSecret, domain, listenAddress, serverName, certificateTTL, hostnamesOrIps)
if err != nil {
util.HandleError(err, "Failed to install systemd service")
}

enableCmd := exec.Command("systemctl", "enable", "infisical-kmip")
if err := enableCmd.Run(); err != nil {
util.HandleError(err, "Failed to enable systemd service")
}

log.Info().Msg("Successfully installed and enabled infisical-kmip service")
log.Info().Msg("To start the service, run: sudo systemctl start infisical-kmip")
},
}

var kmipSystemdUninstallCmd = &cobra.Command{
Use: "uninstall",
Short: "Uninstall and remove systemd service for the KMIP server (requires sudo)",
Long: "Uninstall and remove systemd service for the KMIP server. Must be run with sudo on Linux.",
Example: "sudo infisical kmip systemd uninstall",
DisableFlagsInUseLine: true,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
if runtime.GOOS != "linux" {
util.HandleError(fmt.Errorf("systemd service installation is only supported on Linux"))
}

if os.Geteuid() != 0 {
util.HandleError(fmt.Errorf("systemd service installation requires root/sudo privileges"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be "systemd service uninstallation requires root/sudo privileges"

}

if err := localkmip.UninstallKmipSystemdService(); err != nil {
util.HandleError(err, "Failed to uninstall systemd service")
}
},
}

func init() {
// KMIP start command flags
kmipStartCmd.Flags().String("listen-address", "localhost:5696", "The address for the KMIP server to listen on. Defaults to localhost:5696")
kmipStartCmd.Flags().String("identity-auth-method", string(util.AuthStrategy.UNIVERSAL_AUTH), "The auth method to use for authenticating the machine identity. Defaults to universal-auth.")
kmipStartCmd.Flags().String("identity-client-id", "", "Universal auth client ID of machine identity")
kmipStartCmd.Flags().String("identity-client-secret", "", "Universal auth client secret of machine identity")
kmipStartCmd.Flags().String("server-name", "kmip-server", "The name of the KMIP server")
kmipStartCmd.Flags().String("certificate-ttl", "1y", "The TTL duration for the server certificate")
kmipStartCmd.Flags().String("server-name", "kmip-server", "The name of the KMIP server. Defaults to kmip-server")
kmipStartCmd.Flags().String("certificate-ttl", "1y", "The TTL duration for the server certificate. Defaults to 1y")
kmipStartCmd.Flags().String("hostnames-or-ips", "", "Comma-separated list of hostnames or IPs")

// KMIP systemd install command flags
kmipSystemdInstallCmd.Flags().String("identity-client-id", "", "Universal auth client ID of machine identity")
kmipSystemdInstallCmd.Flags().String("identity-client-secret", "", "Universal auth client secret of machine identity")
kmipSystemdInstallCmd.Flags().String("domain", "", "Domain of your self-hosted Infisical instance")
kmipSystemdInstallCmd.Flags().String("listen-address", "", "The address for the KMIP server to listen on")
kmipSystemdInstallCmd.Flags().String("server-name", "", "The name of the KMIP server")
kmipSystemdInstallCmd.Flags().String("certificate-ttl", "", "The TTL duration for the server certificate")
kmipSystemdInstallCmd.Flags().String("hostnames-or-ips", "", "Comma-separated list of hostnames or IPs")

// Wire up command hierarchy
kmipSystemdCmd.AddCommand(kmipSystemdInstallCmd)
kmipSystemdCmd.AddCommand(kmipSystemdUninstallCmd)

kmipCmd.AddCommand(kmipStartCmd)
kmipCmd.AddCommand(kmipSystemdCmd)
RootCmd.AddCommand(kmipCmd)
}
134 changes: 134 additions & 0 deletions packages/kmip/systemd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package kmip

import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"

"github.com/rs/zerolog/log"
)

const systemdServiceTemplate = `[Unit]
Description=Infisical KMIP Server Service
After=network.target

[Service]
Type=simple
EnvironmentFile=/etc/infisical/kmip.conf
ExecStart=infisical kmip start
Restart=on-failure
InaccessibleDirectories=/home
PrivateTmp=yes
LimitCORE=infinity
LimitNOFILE=1000000
LimitNPROC=60000
LimitRTPRIO=infinity
LimitRTTIME=7000000

[Install]
WantedBy=multi-user.target
`

func InstallKmipSystemdService(clientId, clientSecret, domain, listenAddress, serverName, certificateTTL, hostnamesOrIps string) error {
if runtime.GOOS != "linux" {
log.Info().Msg("Skipping systemd service installation - not on Linux")
return nil
}

if os.Geteuid() != 0 {
log.Info().Msg("Skipping systemd service installation - not running as root/sudo")
return nil
}

configDir := "/etc/infisical"
if err := os.MkdirAll(configDir, 0755); err != nil {
return fmt.Errorf("failed to create config directory: %v", err)
}

configContent := fmt.Sprintf("INFISICAL_UNIVERSAL_AUTH_CLIENT_ID=%s\n", clientId)
configContent += fmt.Sprintf("INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET=%s\n", clientSecret)

if domain != "" {
configContent += fmt.Sprintf("INFISICAL_API_URL=%s\n", domain)
}
if listenAddress != "" {
configContent += fmt.Sprintf("INFISICAL_KMIP_LISTEN_ADDRESS=%s\n", listenAddress)
}
if serverName != "" {
configContent += fmt.Sprintf("INFISICAL_KMIP_SERVER_NAME=%s\n", serverName)
}
if certificateTTL != "" {
configContent += fmt.Sprintf("INFISICAL_KMIP_CERTIFICATE_TTL=%s\n", certificateTTL)
}
if hostnamesOrIps != "" {
configContent += fmt.Sprintf("INFISICAL_KMIP_HOSTNAMES_OR_IPS=%s\n", hostnamesOrIps)
}

configPath := filepath.Join(configDir, "kmip.conf")
if err := os.WriteFile(configPath, []byte(configContent), 0600); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we quote the env variable? If configPath contains spaces then it would break right?

return fmt.Errorf("failed to write config file: %v", err)
}

servicePath := "/etc/systemd/system/infisical-kmip.service"
if err := os.WriteFile(servicePath, []byte(systemdServiceTemplate), 0644); err != nil {
return fmt.Errorf("failed to write systemd service file: %v", err)
}

reloadCmd := exec.Command("systemctl", "daemon-reload")
if err := reloadCmd.Run(); err != nil {
return fmt.Errorf("failed to reload systemd: %v", err)
}

log.Info().Msg("Successfully installed systemd service")
log.Info().Msg("To start the service, run: sudo systemctl start infisical-kmip")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm curious, I see in a previous function we're running enableCmd := exec.Command("systemctl", "enable", "infisical-kmip") but on this one we are relying on the user to run it manually, any reason why this one is different?

log.Info().Msg("To enable the service on boot, run: sudo systemctl enable infisical-kmip")

return nil
}

func UninstallKmipSystemdService() error {
if runtime.GOOS != "linux" {
log.Info().Msg("Skipping systemd service uninstallation - not on Linux")
return nil
}

if os.Geteuid() != 0 {
log.Info().Msg("Skipping systemd service uninstallation - not running as root/sudo")
return nil
}

// Stop the service if it's running
stopCmd := exec.Command("systemctl", "stop", "infisical-kmip")
if err := stopCmd.Run(); err != nil {
log.Warn().Msgf("Failed to stop service: %v", err)
}

// Disable the service
disableCmd := exec.Command("systemctl", "disable", "infisical-kmip")
if err := disableCmd.Run(); err != nil {
log.Warn().Msgf("Failed to disable service: %v", err)
}

// Remove the service file
servicePath := "/etc/systemd/system/infisical-kmip.service"
if err := os.Remove(servicePath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed to remove systemd service file: %v", err)
}

// Remove the configuration file
configPath := "/etc/infisical/kmip.conf"
if err := os.Remove(configPath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed to remove config file: %v", err)
}

// Reload systemd to apply changes
reloadCmd := exec.Command("systemctl", "daemon-reload")
if err := reloadCmd.Run(); err != nil {
return fmt.Errorf("failed to reload systemd: %v", err)
}

log.Info().Msg("Successfully uninstalled Infisical KMIP systemd service")
return nil
}
1 change: 1 addition & 0 deletions packages/util/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (

// Generic env variable used for auth methods that require a machine identity ID
INFISICAL_MACHINE_IDENTITY_ID_NAME = "INFISICAL_MACHINE_IDENTITY_ID"
INFISICAL_API_URL_ENV_NAME = "INFISICAL_API_URL"

SECRET_TYPE_PERSONAL = "personal"
SECRET_TYPE_SHARED = "shared"
Expand Down
Loading