
本教程详细介绍了如何使用go语言生成ssh密钥对,重点在于创建符合openssh `authorized_keys`文件格式的公钥。文章将引导读者从rsa私钥的生成,到其pem编码存储,再到通过`golang.org/x/crypto/ssh`包将公钥转换为openssh标准格式并保存,提供完整的代码示例和最佳实践,确保密钥的安全性和兼容性。
Go语言生成SSH密钥对:从RSA到OpenSSH格式
在Go语言中进行安全通信或自动化部署时,经常需要程序化地生成SSH密钥对。虽然Go标准库提供了生成RSA密钥和PEM编码的功能,但要生成符合OpenSSH authorized_keys文件格式的公钥,则需要借助额外的包。本教程将详细介绍如何生成一个RSA私钥,并将其对应的公钥转换为OpenSSH可识别的格式。
1. 理解SSH密钥对和格式差异
SSH密钥对由一个私钥和一个公钥组成。私钥需要严格保密,而公钥则可以公开。当客户端尝试通过SSH连接到服务器时,服务器会使用存储在其authorized_keys文件中的公钥来验证客户端的私钥。
Go标准库中的crypto/rsa和crypto/x509包可以生成和处理RSA密钥,并将其编码为PKCS#1或PKIX格式的PEM块。然而,OpenSSH的authorized_keys文件对公钥的格式有特定的要求,它通常以ssh-rsa AAAAB3Nz…这样的字符串开头,而不是标准的PEM编码。
2. 生成RSA私钥
首先,我们需要生成一个RSA私钥。这是密钥对的基础。rsa.GenerateKey函数用于生成指定位数的RSA私钥。
立即学习“go语言免费学习笔记(深入)”;
package mainimport ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "io/ioutil" "os" "golang.org/x/crypto/ssh" // 导入用于OpenSSH格式公钥的包)// generatePrivateKey 生成指定位数的RSA私钥func generatePrivateKey(bits int) (*rsa.PrivateKey, error) { privateKey, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return nil, fmt.Errorf("生成RSA私钥失败: %w", err) } return privateKey, nil}
注意事项:
rand.Reader是Go语言中加密安全的随机数源,用于生成密钥的随机部分。密钥位数(bits)通常建议选择2048或4096位,以提供足够的安全性。
3. PEM编码私钥并保存
生成私钥后,通常将其编码为PEM格式并保存到文件中。PEM是一种文本编码格式,常用于存储加密密钥和证书。
// encodeAndSavePrivateKey 将RSA私钥编码为PEM格式并保存到文件func encodeAndSavePrivateKey(privateKey *rsa.PrivateKey, path string) error { // 将RSA私钥转换为PKCS#1 DER编码 privateKeyDER := x509.MarshalPKCS1PrivateKey(privateKey) // 创建PEM编码块 privateKeyBlock := &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: privateKeyDER, } // 将PEM编码写入文件 privateKeyFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) // 权限设置为0600确保私钥安全 if err != nil { return fmt.Errorf("创建私钥文件失败: %w", err) } defer privateKeyFile.Close() if err := pem.Encode(privateKeyFile, privateKeyBlock); err != nil { return fmt.Errorf("PEM编码私钥失败: %w", err) } return nil}
注意事项:
私钥文件的权限应设置为0600(只有文件所有者可读写),以防止未经授权的访问。这是SSH密钥管理的最佳实践。x509.MarshalPKCS1PrivateKey用于将rsa.PrivateKey转换为PKCS#1 DER编码的字节切片。pem.Encode将PEM块写入输出流。
4. 生成OpenSSH格式的公钥
这是本教程的核心部分。Go标准库的crypto/rsa包生成的rsa.PublicKey无法直接用于OpenSSH的authorized_keys文件。我们需要使用golang.org/x/crypto/ssh包来完成转换。
// generateAndSavePublicKey 将RSA公钥转换为OpenSSH格式并保存到文件func generateAndSavePublicKey(privateKey *rsa.PrivateKey, path string) error { // 从RSA私钥中提取公钥 publicKey := &privateKey.PublicKey // 使用golang.org/x/crypto/ssh将RSA公钥转换为OpenSSH格式 sshPublicKey, err := ssh.NewPublicKey(publicKey) if err != nil { return fmt.Errorf("转换为OpenSSH公钥格式失败: %w", err) } // 将OpenSSH公钥编码为authorized_keys文件所需的格式 authorizedKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey) // 将公钥写入文件 // 注意:OpenSSH公钥文件的权限通常可以放宽,但0644是一个常见且安全的选择 if err := ioutil.WriteFile(path, authorizedKeyBytes, 0644); err != nil { return fmt.Errorf("写入OpenSSH公钥文件失败: %w", err) } return nil}
关键函数:
ssh.NewPublicKey(publicKey *rsa.PublicKey): 这个函数接收一个*rsa.PublicKey(或其他加密算法的公钥),并返回一个ssh.PublicKey接口类型。这是将标准Go公钥转换为golang.org/x/crypto/ssh包内部表示的关键一步。ssh.MarshalAuthorizedKey(pub ssh.PublicKey): 这个函数将ssh.PublicKey接口编码为OpenSSH authorized_keys文件所需的字节切片。它会自动添加ssh-rsa前缀和密钥内容。
5. 完整示例代码
将上述函数组合起来,可以创建一个完整的程序来生成SSH密钥对并保存到指定文件。
package mainimport ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "io/ioutil" "os" "path/filepath" "golang.org/x/crypto/ssh")// generatePrivateKey 生成指定位数的RSA私钥func generatePrivateKey(bits int) (*rsa.PrivateKey, error) { privateKey, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return nil, fmt.Errorf("生成RSA私钥失败: %w", err) } return privateKey, nil}// encodeAndSavePrivateKey 将RSA私钥编码为PEM格式并保存到文件func encodeAndSavePrivateKey(privateKey *rsa.PrivateKey, path string) error { privateKeyDER := x509.MarshalPKCS1PrivateKey(privateKey) privateKeyBlock := &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: privateKeyDER, } privateKeyFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return fmt.Errorf("创建私钥文件失败: %w", err) } defer privateKeyFile.Close() if err := pem.Encode(privateKeyFile, privateKeyBlock); err != nil { return fmt.Errorf("PEM编码私钥失败: %w", err) } return nil}// generateAndSavePublicKey 将RSA公钥转换为OpenSSH格式并保存到文件func generateAndSavePublicKey(privateKey *rsa.PrivateKey, path string) error { publicKey := &privateKey.PublicKey sshPublicKey, err := ssh.NewPublicKey(publicKey) if err != nil { return fmt.Errorf("转换为OpenSSH公钥格式失败: %w", err) } authorizedKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey) if err := ioutil.WriteFile(path, authorizedKeyBytes, 0644); err != nil { return fmt.Errorf("写入OpenSSH公钥文件失败: %w", err) } return nil}// MakeSSHKeyPair 是一个辅助函数,用于生成SSH密钥对并保存到指定路径func MakeSSHKeyPair(pubKeyPath, privateKeyPath string) error { // 1. 生成RSA私钥 (建议使用2048或4096位) privateKey, err := generatePrivateKey(2048) if err != nil { return err } // 2. 保存PEM编码的私钥 if err := encodeAndSavePrivateKey(privateKey, privateKeyPath); err != nil { return err } // 3. 生成并保存OpenSSH格式的公钥 if err := generateAndSavePublicKey(privateKey, pubKeyPath); err != nil { return err } return nil}func main() { // 定义密钥文件的路径 homeDir, err := os.UserHomeDir() if err != nil { fmt.Printf("获取用户主目录失败: %vn", err) os.Exit(1) } keyDir := filepath.Join(homeDir, ".ssh_go_keys") if err := os.MkdirAll(keyDir, 0700); err != nil { fmt.Printf("创建密钥目录失败: %vn", err) os.Exit(1) } privateKeyFile := filepath.Join(keyDir, "id_rsa_go") publicKeyFile := filepath.Join(keyDir, "id_rsa_go.pub") fmt.Printf("正在生成SSH密钥对...n私钥: %sn公钥: %sn", privateKeyFile, publicKeyFile) if err := MakeSSHKeyPair(publicKeyFile, privateKeyFile); err != nil { fmt.Printf("生成SSH密钥对失败: %vn", err) os.Exit(1) } fmt.Println("SSH密钥对生成成功!") // 验证生成的文件内容 (可选) privateKeyContent, err := ioutil.ReadFile(privateKeyFile) if err != nil { fmt.Printf("读取私钥文件失败: %vn", err) } else { fmt.Println("n--- 私钥内容 (部分) ---") fmt.Println(string(privateKeyContent[:200]) + "...") // 打印前200字节 } publicKeyContent, err := ioutil.ReadFile(publicKeyFile) if err != nil { fmt.Printf("读取公钥文件失败: %vn", err) } else { fmt.Println("n--- 公钥内容 ---") fmt.Println(string(publicKeyContent)) }}
运行示例:
确保你已经安装了Go环境。在你的Go模块中运行 go get golang.org/x/crypto/ssh 来安装所需的第三方包。将上述代码保存为 main.go。运行 go run main.go。程序将在你的用户主目录下创建一个.ssh_go_keys目录,并在其中生成id_rsa_go(私钥)和id_rsa_go.pub(公钥)。
总结
通过利用Go标准库的crypto/rsa和crypto/x509包来生成和PEM编码私钥,并结合golang.org/x/crypto/ssh包来生成OpenSSH兼容的公钥,我们可以轻松地在Go程序中实现SSH密钥对的自动化生成。遵循文件权限等安全最佳实践,可以确保所生成密钥的安全性。
以上就是Go语言生成OpenSSH兼容的SSH密钥对教程的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1424998.html
微信扫一扫
支付宝扫一扫