Skip to content

Commit

Permalink
Merge pull request #24 from Infisical/ssh-cert
Browse files Browse the repository at this point in the history
Add SSH issue and sign operations to SDK
  • Loading branch information
dangtony98 authored Dec 14, 2024
2 parents fc1d696 + d68500d commit 318b41b
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 0 deletions.
7 changes: 7 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type InfisicalClient struct {
auth AuthInterface
dynamicSecrets DynamicSecretsInterface
kms KmsInterface
ssh SshInterface
}

type InfisicalClientInterface interface {
Expand All @@ -43,6 +44,7 @@ type InfisicalClientInterface interface {
Auth() AuthInterface
DynamicSecrets() DynamicSecretsInterface
Kms() KmsInterface
Ssh() SshInterface
}

type Config struct {
Expand Down Expand Up @@ -120,6 +122,7 @@ func NewInfisicalClient(context context.Context, config Config) InfisicalClientI
client.auth = NewAuth(client)
client.dynamicSecrets = NewDynamicSecrets(client)
client.kms = NewKms(client)
client.ssh = NewSsh(client)

if config.AutoTokenRefresh {
go client.handleTokenLifeCycle(context)
Expand Down Expand Up @@ -185,6 +188,10 @@ func (c *InfisicalClient) Kms() KmsInterface {
return c.kms
}

func (c *InfisicalClient) Ssh() SshInterface {
return c.ssh
}

func (c *InfisicalClient) handleTokenLifeCycle(context context.Context) {
var warningPrinted = false
authStrategies := map[util.AuthMethod]func(cred interface{}) (credential MachineIdentityCredential, err error){
Expand Down
27 changes: 27 additions & 0 deletions packages/api/ssh/issue_ssh_creds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package api

import (
"github.com/go-resty/resty/v2"
"github.com/infisical/go-sdk/packages/errors"
)

const callIssueSshCredsOperation = "CallIssueSshCredsV1"

func CallIssueSshCredsV1(httpClient *resty.Client, request IssueSshCredsV1Request) (IssueSshCredsV1Response, error) {
issueSshCredsResponse := IssueSshCredsV1Response{}

res, err := httpClient.R().
SetResult(&issueSshCredsResponse).
SetBody(request).
Post("/v1/ssh/issue")

if err != nil {
return IssueSshCredsV1Response{}, errors.NewRequestError(callIssueSshCredsOperation, err)
}

if res.IsError() {
return IssueSshCredsV1Response{}, errors.NewAPIErrorWithResponse(callIssueSshCredsOperation, res)
}

return issueSshCredsResponse, nil
}
39 changes: 39 additions & 0 deletions packages/api/ssh/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package api

import (
"github.com/infisical/go-sdk/packages/util"
)

type SignSshPublicKeyV1Request struct {
ProjectID string `json:"projectId"`
TemplateName string `json:"templateName"`
PublicKey string `json:"publicKey"`
KeyAlgorithm util.CertKeyAlgorithm `json:"keyAlgorithm,omitempty"`
CertType util.SshCertType `json:"certType,omitempty"`
Principals []string `json:"principals"`
TTL string `json:"ttl,omitempty"`
KeyID string `json:"keyId,omitempty"`
}

type SignSshPublicKeyV1Response struct {
SerialNumber string `json:"serialNumber"`
SignedKey string `json:"signedKey"`
}

type IssueSshCredsV1Request struct {
ProjectID string `json:"projectId"`
TemplateName string `json:"templateName"`
KeyAlgorithm util.CertKeyAlgorithm `json:"keyAlgorithm,omitempty"`
CertType util.SshCertType `json:"certType,omitempty"`
Principals []string `json:"principals"`
TTL string `json:"ttl,omitempty"`
KeyID string `json:"keyId,omitempty"`
}

type IssueSshCredsV1Response struct {
SerialNumber string `json:"serialNumber"`
SignedKey string `json:"signedKey"`
PrivateKey string `json:"privateKey"`
PublicKey string `json:"publicKey"`
KeyAlgorithm util.CertKeyAlgorithm `json:"keyAlgorithm"`
}
27 changes: 27 additions & 0 deletions packages/api/ssh/sign_ssh_public_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package api

import (
"github.com/go-resty/resty/v2"
"github.com/infisical/go-sdk/packages/errors"
)

const callSignSshPublicKeyOperation = "CallSignSshPublicKeyV1"

func CallSignSshPublicKeyV1(httpClient *resty.Client, request SignSshPublicKeyV1Request) (SignSshPublicKeyV1Response, error) {
signSshPublicKeyResponse := SignSshPublicKeyV1Response{}

res, err := httpClient.R().
SetResult(&signSshPublicKeyResponse).
SetBody(request).
Post("/v1/ssh/sign")

if err != nil {
return SignSshPublicKeyV1Response{}, errors.NewRequestError(callSignSshPublicKeyOperation, err)
}

if res.IsError() {
return SignSshPublicKeyV1Response{}, errors.NewAPIErrorWithResponse(callSignSshPublicKeyOperation, res)
}

return signSshPublicKeyResponse, nil
}
17 changes: 17 additions & 0 deletions packages/util/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ const (
OIDC_AUTH AuthMethod = "OIDC_AUTH"
)

// SSH related:
type CertKeyAlgorithm string

const (
RSA2048 CertKeyAlgorithm = "RSA_2048"
RSA4096 CertKeyAlgorithm = "RSA_4096"
ECDSAP256 CertKeyAlgorithm = "EC_prime256v1"
ECDSAP384 CertKeyAlgorithm = "EC_secp384r1"
)

type SshCertType string

const (
UserCert SshCertType = "user"
HostCert SshCertType = "host"
)

// General:
const (
DEFAULT_INFISICAL_API_URL = "https://app.infisical.com/api"
Expand Down
41 changes: 41 additions & 0 deletions ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package infisical

import (
api "github.com/infisical/go-sdk/packages/api/ssh"
)

type SignSshPublicKeyOptions = api.SignSshPublicKeyV1Request
type IssueSshCredsOptions = api.IssueSshCredsV1Request

type SshInterface interface {
SignKey(options SignSshPublicKeyOptions) (api.SignSshPublicKeyV1Response, error)
IssueCredentials(options IssueSshCredsOptions) (api.IssueSshCredsV1Response, error)
}

type Ssh struct {
client *InfisicalClient
}

func (f *Ssh) SignKey(options SignSshPublicKeyOptions) (api.SignSshPublicKeyV1Response, error) {
res, err := api.CallSignSshPublicKeyV1(f.client.httpClient, options)

if err != nil {
return api.SignSshPublicKeyV1Response{}, err
}

return res, nil
}

func (f *Ssh) IssueCredentials(options IssueSshCredsOptions) (api.IssueSshCredsV1Response, error) {
res, err := api.CallIssueSshCredsV1(f.client.httpClient, options)

if err != nil {
return api.IssueSshCredsV1Response{}, err
}

return res, nil
}

func NewSsh(client *InfisicalClient) SshInterface {
return &Ssh{client: client}
}
50 changes: 50 additions & 0 deletions test/ssh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package test

// import (
// "context"
// "fmt"
// "os"
// "testing"

// infisical "github.com/infisical/go-sdk"
// )

// func TestSshIssueCreds(t *testing.T) {
// client := infisical.NewInfisicalClient(context.Background(), infisical.Config{
// SiteUrl: "http://localhost:8080",
// AutoTokenRefresh: true,
// })

// // Authenticate using Universal Auth
// _, err := client.Auth().UniversalAuthLogin(os.Getenv("GO_SDK_TEST_UNIVERSAL_AUTH_CLIENT_ID"), os.Getenv("GO_SDK_TEST_UNIVERSAL_AUTH_CLIENT_SECRET"))
// if err != nil {
// fmt.Printf("Authentication failed: %v\n", err)
// os.Exit(1)
// }

// // Test issuing SSH credentials
// creds, err := client.Ssh().IssueCredentials(infisical.IssueSshCredsOptions{
// ProjectID: os.Getenv("GO_SDK_TEST_PROJECT_ID"),
// TemplateName: "template-name",
// Principals: []string{"ec2-user"},
// })

// if err != nil {
// t.Fatalf("Failed to issue SSH credentials: %v", err)
// }

// // Test signing SSH public key
// creds2, err := client.Ssh().SignKey(infisical.SignSshPublicKeyOptions{
// ProjectID: os.Getenv("GO_SDK_TEST_PROJECT_ID"),
// TemplateName: "template-name",
// Principals: []string{"ec2-user"},
// PublicKey: "ssh-rsa ...",
// })

// if err != nil {
// t.Fatalf("Failed to sign SSH public key: %v", err)
// }

// fmt.Print("Newly-issued SSH credentials: ", creds)
// fmt.Print("Signed SSH credential: ", creds2)
// }

0 comments on commit 318b41b

Please sign in to comment.