Skip to content

Commit

Permalink
Export ssh public keys under ssh-pub-keys in topo json (#2387)
Browse files Browse the repository at this point in the history
* export ssh public keys under ssh-pub-keys in topo json

* move ssh pub keys out of clab config tree
  • Loading branch information
hellt authored Jan 11, 2025
1 parent dd321ab commit 38ea59a
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 82 deletions.
12 changes: 8 additions & 4 deletions clab/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import (

log "github.com/sirupsen/logrus"
"github.com/srl-labs/containerlab/types"
"github.com/srl-labs/containerlab/utils"
)

// GenerateExports generates various export files and writes it to a lab location.
// GenerateExports generates various export files and writes it to a file in the lab directory.
func (c *CLab) GenerateExports(ctx context.Context, f io.Writer, p string) error {
err := c.exportTopologyDataWithTemplate(ctx, f, p)
if err != nil {
Expand All @@ -36,9 +37,11 @@ func (c *CLab) GenerateExports(ctx context.Context, f io.Writer, p string) error
// TopologyExport holds a combination of CLab structure and map of NodeConfig types,
// which expands Node definitions with dynamically created values.
type TopologyExport struct {
Name string `json:"name"`
Type string `json:"type"`
Clab *CLab `json:"clab,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
Clab *CLab `json:"clab,omitempty"`
// SSHPubKeys is a list of string representations of SSH public keys.
SSHPubKeys []string `json:"SSHPubKeys,omitempty"`
NodeConfigs map[string]*types.NodeConfig `json:"nodeconfigs,omitempty"`
}

Expand Down Expand Up @@ -87,6 +90,7 @@ func (c *CLab) exportTopologyDataWithTemplate(_ context.Context, w io.Writer, p
Name: c.Config.Name,
Type: "clab",
Clab: c,
SSHPubKeys: utils.MarshalSSHPubKeys(c.SSHPubKeys),
NodeConfigs: make(map[string]*types.NodeConfig),
}

Expand Down
1 change: 1 addition & 0 deletions clab/export_templates/auto.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"mgmt": {{ ToJSONPretty .Clab.Config.Mgmt " " " "}}
}
},
"ssh-pub-keys": {{ ToJSON .SSHPubKeys }},
"nodes": { {{- $i:=0 }}{{range $n, $c := .NodeConfigs}}{{if $i}},{{end}}
"{{$n}}": {
"index": "{{$c.Index}}",
Expand Down
1 change: 1 addition & 0 deletions clab/export_templates/full.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "{{ .Name }}",
"type": "{{ .Type }}",
"clab": {{ ToJSONPretty .Clab " " " "}},
"ssh-pub-keys": {{ ToJSON .SSHPubKeys }},
"nodes": { {{- $i:=0 }}{{range $n, $c := .NodeConfigs}}{{if $i}},{{end}}{{ $k := dict "tls-key" $c.TLSKey }}
"{{$n}}":{{ $cj := $c | data.ToJSON | data.JSON }} {{ $dst := coll.Merge $cj $k }}{{ ToJSONPretty $dst " " " " }}{{$i = add $i 1}}{{end}}
},
Expand Down
32 changes: 0 additions & 32 deletions nodes/srl/sshkey.go

This file was deleted.

45 changes: 0 additions & 45 deletions nodes/srl/sshkey_test.go

This file was deleted.

3 changes: 2 additions & 1 deletion nodes/srl/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

log "github.com/sirupsen/logrus"
"github.com/srl-labs/containerlab/clab/exec"
"github.com/srl-labs/containerlab/utils"
"golang.org/x/mod/semver"
)

Expand Down Expand Up @@ -163,7 +164,7 @@ func (n *srl) setVersionSpecificParams(tplData *srlTemplateData) {
// in srlinux >= v23.10+ linuxadmin and admin user ssh keys can only be configured via the cli
// so we add the keys to the template data for rendering.
if len(n.sshPubKeys) > 0 && (semver.Compare(v, "v23.10") >= 0 || n.swVersion.Major == "0") {
tplData.SSHPubKeys = catenateKeys(n.sshPubKeys)
tplData.SSHPubKeys = utils.MarshalAndCatenateSSHPubKeys(n.sshPubKeys)
}

// in srlinux >= v24.3+ we add ACL rules to enable http and telnet access
Expand Down
34 changes: 34 additions & 0 deletions utils/ssh.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package utils

import (
"bytes"
"os/exec"
"regexp"
"strings"

log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)

// GetSSHVersion returns the version of the ssh client
Expand Down Expand Up @@ -32,3 +35,34 @@ func parseSSHVersion(in string) string {

return match[1]
}

// MarshalSSHPubKeys marshales the ssh public keys
// and a string slice that contains string representations of the keys.
func MarshalSSHPubKeys(in []ssh.PublicKey) []string {
r := []string{}

for _, k := range in {
// extract the keys in AuthorizedKeys format (e.g. "ssh-rsa <KEY>")
ks := bytes.TrimSpace(ssh.MarshalAuthorizedKey(k))
r = append(r, string(ks))

}

return r
}

// MarshalAndCatenateSSHPubKeys catenates the ssh public keys
// and produces a string that can be used in the
// cli config command to set the ssh public keys
// for users.
// Each key value in the catenated string will be double quoted.
func MarshalAndCatenateSSHPubKeys(in []ssh.PublicKey) string {
keysSlice := MarshalSSHPubKeys(in)
quotedKeys := make([]string, len(keysSlice))

for i, k := range keysSlice {
quotedKeys[i] = "\"" + k + "\""
}

return strings.Join(quotedKeys, " ")
}
35 changes: 35 additions & 0 deletions utils/ssh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package utils

import (
"testing"

"github.com/google/go-cmp/cmp"
)

func TestParseSSHVersion(t *testing.T) {
Expand Down Expand Up @@ -36,3 +38,36 @@ func TestParseSSHVersion(t *testing.T) {
})
}
}

func Test_MarshalAndCatenateSSHPubKeys(t *testing.T) {
type fields struct {
keyFiles []string
}
tests := []struct {
name string
fields fields
want string
}{
{
name: "test1",
fields: fields{
keyFiles: []string{"test_data/keys"},
},
want: "\"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs4Qv1yrBk6ygt+o7J4sUcYv+WfDjdAyABDoinOt3PgSmCcVqqAP2qS8UtTnMNuy93Orp6+/R/7/R3O5xdY6I4YViK3WVlKTAUVm7vdeTKp9uq1tNeWgo7+J3baSbQ3INp85ScTfFvRzRCFkr/W97Wh6pTa7ysgkcPvc2/tXG2z36Mx7/TFBk3Q1LY3ByKLtGrC5JnVpMTrqrsCwcLEVHHEZ4z5R4FZED/lpz+wTNFnR/l9HA6yDkKYensHynx+guqYpYD6y4yEGY/LcUnwBg0zIlUhmOsvdmxWBz12Lp7EBiNjSwhnPfe+o3efLGGnjWUAa4TgO8Sa8PQP0pK/ZNd\" \"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILKdXYzPIq8kHRJtDrh21wMVI76AnuPk7HDLeDteKN74\"",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
keys, err := LoadSSHPubKeysFromFiles(tt.fields.keyFiles)
if err != nil {
t.Errorf("failed to load keys: %v", err)
}

got := MarshalAndCatenateSSHPubKeys(keys)

if d := cmp.Diff(got, tt.want); d != "" {
t.Errorf("MarshalAndCatenateSSHPubKeys() = %s", d)
}
})
}
}
File renamed without changes.

0 comments on commit 38ea59a

Please sign in to comment.