-
Notifications
You must be signed in to change notification settings - Fork 22
feat: kmip systemd install #139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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, | ||
|
|
@@ -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") | ||
|
|
@@ -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") | ||
| } | ||
|
|
@@ -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{ | ||
|
|
@@ -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")) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
| } | ||
| 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 { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm curious, I see in a previous function we're running |
||
| log.Info().Msg("To enable the service on boot, run: sudo systemctl enable infisical-kmip") | ||
sheensantoscapadngan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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 | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.