Skip to content
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

Add SSH issue and sign operations to SDK #24

Merged
merged 5 commits into from
Dec 14, 2024
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
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)
// }
Loading