Skip to content

Commit d0784a2

Browse files
Merge pull request openshift#8105 from pawanpinjarkar/generate-ecdsa-keys
AGENT-868: Generate ECDSA public private keys and pass it to assisted service
2 parents 0645657 + 0c0ced2 commit d0784a2

File tree

5 files changed

+150
-4
lines changed

5 files changed

+150
-4
lines changed

data/data/agent/files/usr/local/share/assisted-service/assisted-service.env.template

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ RELEASE_IMAGES={{.ReleaseImages}}
1818
OPENSHIFT_INSTALL_RELEASE_IMAGE_MIRROR={{.ReleaseImageMirror}}
1919
STORAGE=filesystem
2020
INFRA_ENV_ID={{.InfraEnvID}}
21+
EC_PUBLIC_KEY_PEM={{.PublicKeyPEM}}
22+
EC_PRIVATE_KEY_PEM={{.PrivateKeyPEM}}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package gencrypto
2+
3+
import (
4+
"bytes"
5+
"crypto/ecdsa"
6+
"crypto/elliptic"
7+
"crypto/rand"
8+
"crypto/x509"
9+
"encoding/pem"
10+
11+
"github.com/openshift/installer/pkg/asset"
12+
)
13+
14+
// AuthConfig is an asset that generates ECDSA public and private keys.
15+
type AuthConfig struct {
16+
PublicKey, PrivateKey string
17+
}
18+
19+
var _ asset.WritableAsset = (*AuthConfig)(nil)
20+
21+
// Dependencies returns the assets on which the AuthConfig asset depends.
22+
func (a *AuthConfig) Dependencies() []asset.Asset {
23+
return []asset.Asset{}
24+
}
25+
26+
// Generate generates the auth config for agent installer APIs.
27+
func (a *AuthConfig) Generate(dependencies asset.Parents) error {
28+
PublicKey, PrivateKey, err := keyPairPEM()
29+
if err != nil {
30+
return err
31+
}
32+
a.PublicKey = PublicKey
33+
a.PrivateKey = PrivateKey
34+
35+
return nil
36+
}
37+
38+
// Name returns the human-friendly name of the asset.
39+
func (a *AuthConfig) Name() string {
40+
return "Agent Installer API Auth Config"
41+
}
42+
43+
// Load returns the auth config from disk.
44+
func (a *AuthConfig) Load(f asset.FileFetcher) (bool, error) {
45+
// The AuthConfig will not be needed by another asset so load is noop.
46+
// This is implemented because it is required by WritableAsset
47+
return false, nil
48+
}
49+
50+
// Files returns the files generated by the asset.
51+
func (a *AuthConfig) Files() []*asset.File {
52+
// Return empty array because File will never be loaded.
53+
return []*asset.File{}
54+
}
55+
56+
// Reused from assisted-service.
57+
// https://github.com/openshift/assisted-service/blob/d3c0122452c74ad208055b8b6ee412812431a83f/internal/gencrypto/keys.go#L13-L54
58+
func keyPairPEM() (string, string, error) {
59+
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
60+
if err != nil {
61+
return "", "", err
62+
}
63+
64+
// encode private key to PEM string
65+
privBytes, err := x509.MarshalECPrivateKey(priv)
66+
if err != nil {
67+
return "", "", err
68+
}
69+
70+
block := &pem.Block{
71+
Type: "EC PRIVATE KEY",
72+
Bytes: privBytes,
73+
}
74+
75+
var privKeyPEM bytes.Buffer
76+
err = pem.Encode(&privKeyPEM, block)
77+
if err != nil {
78+
return "", "", err
79+
}
80+
81+
// encode public key to PEM string
82+
pubBytes, err := x509.MarshalPKIXPublicKey(priv.Public())
83+
if err != nil {
84+
return "", "", err
85+
}
86+
87+
block = &pem.Block{
88+
Type: "EC PUBLIC KEY",
89+
Bytes: pubBytes,
90+
}
91+
92+
var pubKeyPEM bytes.Buffer
93+
err = pem.Encode(&pubKeyPEM, block)
94+
if err != nil {
95+
return "", "", err
96+
}
97+
98+
return pubKeyPEM.String(), privKeyPEM.String(), nil
99+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package gencrypto
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestAuthConfig_Generate(t *testing.T) {
10+
cases := []struct {
11+
name string
12+
}{
13+
{
14+
name: "generate-public-private-keys",
15+
},
16+
}
17+
for _, tc := range cases {
18+
t.Run(tc.name, func(t *testing.T) {
19+
authConfigAsset := &AuthConfig{}
20+
err := authConfigAsset.Generate(nil)
21+
22+
assert.NoError(t, err)
23+
24+
assert.Contains(t, authConfigAsset.PrivateKey, "BEGIN EC PRIVATE KEY")
25+
assert.Contains(t, authConfigAsset.PublicKey, "BEGIN EC PUBLIC KEY")
26+
})
27+
}
28+
}

pkg/asset/agent/image/ignition.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/openshift/installer/pkg/asset"
2424
agentcommon "github.com/openshift/installer/pkg/asset/agent"
2525
"github.com/openshift/installer/pkg/asset/agent/agentconfig"
26+
"github.com/openshift/installer/pkg/asset/agent/gencrypto"
2627
"github.com/openshift/installer/pkg/asset/agent/manifests"
2728
"github.com/openshift/installer/pkg/asset/agent/mirror"
2829
"github.com/openshift/installer/pkg/asset/ignition"
@@ -68,6 +69,8 @@ type agentTemplateData struct {
6869
Proxy *v1beta1.Proxy
6970
ConfigImageFiles string
7071
ImageTypeISO string
72+
PublicKeyPEM string
73+
PrivateKeyPEM string
7174
}
7275

7376
// Name returns the human-friendly name of the asset.
@@ -89,6 +92,7 @@ func (a *Ignition) Dependencies() []asset.Asset {
8992
&agentconfig.AgentHosts{},
9093
&mirror.RegistriesConf{},
9194
&mirror.CaBundle{},
95+
&gencrypto.AuthConfig{},
9296
}
9397
}
9498

@@ -98,7 +102,8 @@ func (a *Ignition) Generate(dependencies asset.Parents) error {
98102
agentConfigAsset := &agentconfig.AgentConfig{}
99103
agentHostsAsset := &agentconfig.AgentHosts{}
100104
extraManifests := &manifests.ExtraManifests{}
101-
dependencies.Get(agentManifests, agentConfigAsset, agentHostsAsset, extraManifests)
105+
keyPairAsset := &gencrypto.AuthConfig{}
106+
dependencies.Get(agentManifests, agentConfigAsset, agentHostsAsset, extraManifests, keyPairAsset)
102107

103108
pwd := &password.KubeadminPassword{}
104109
dependencies.Get(pwd)
@@ -193,7 +198,10 @@ func (a *Ignition) Generate(dependencies asset.Parents) error {
193198
infraEnvID,
194199
osImage,
195200
infraEnv.Spec.Proxy,
196-
imageTypeISO)
201+
imageTypeISO,
202+
keyPairAsset.PrivateKey,
203+
keyPairAsset.PublicKey,
204+
)
197205

198206
err = bootstrap.AddStorageFiles(&config, "/", "agent/files", agentTemplateData)
199207
if err != nil {
@@ -309,7 +317,7 @@ func getTemplateData(name, pullSecret, releaseImageList, releaseImage,
309317
infraEnvID string,
310318
osImage *models.OsImage,
311319
proxy *v1beta1.Proxy,
312-
imageTypeISO string) *agentTemplateData {
320+
imageTypeISO, privateKey, publicKey string) *agentTemplateData {
313321
return &agentTemplateData{
314322
ServiceProtocol: "http",
315323
PullSecret: pullSecret,
@@ -325,6 +333,8 @@ func getTemplateData(name, pullSecret, releaseImageList, releaseImage,
325333
OSImage: osImage,
326334
Proxy: proxy,
327335
ImageTypeISO: imageTypeISO,
336+
PrivateKeyPEM: privateKey,
337+
PublicKeyPEM: publicKey,
328338
}
329339
}
330340

pkg/asset/agent/image/ignition_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
hivev1 "github.com/openshift/hive/apis/hive/v1"
2222
"github.com/openshift/installer/pkg/asset"
2323
"github.com/openshift/installer/pkg/asset/agent/agentconfig"
24+
"github.com/openshift/installer/pkg/asset/agent/gencrypto"
2425
"github.com/openshift/installer/pkg/asset/agent/manifests"
2526
"github.com/openshift/installer/pkg/asset/agent/mirror"
2627
"github.com/openshift/installer/pkg/asset/password"
@@ -86,7 +87,10 @@ func TestIgnition_getTemplateData(t *testing.T) {
8687
}
8788
clusterName := "test-agent-cluster-install.test"
8889

89-
templateData := getTemplateData(clusterName, pullSecret, releaseImageList, releaseImage, releaseImageMirror, haveMirrorConfig, publicContainerRegistries, agentClusterInstall, infraEnvID, osImage, proxy, "minimal-iso")
90+
privateKey := "-----BEGIN EC PUBLIC KEY-----\nMFkwEwYHKoAiDHV4tg==\n-----END EC PUBLIC KEY-----\n"
91+
publicKey := "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIOSCfDNmx0qe6dncV4tg==\n-----END EC PRIVATE KEY-----\n"
92+
93+
templateData := getTemplateData(clusterName, pullSecret, releaseImageList, releaseImage, releaseImageMirror, haveMirrorConfig, publicContainerRegistries, agentClusterInstall, infraEnvID, osImage, proxy, "minimal-iso", privateKey, publicKey)
9094
assert.Equal(t, clusterName, templateData.ClusterName)
9195
assert.Equal(t, "http", templateData.ServiceProtocol)
9296
assert.Equal(t, pullSecret, templateData.PullSecret)
@@ -100,6 +104,8 @@ func TestIgnition_getTemplateData(t *testing.T) {
100104
assert.Equal(t, infraEnvID, templateData.InfraEnvID)
101105
assert.Equal(t, osImage, templateData.OSImage)
102106
assert.Equal(t, proxy, templateData.Proxy)
107+
assert.Equal(t, privateKey, templateData.PrivateKeyPEM)
108+
assert.Equal(t, publicKey, templateData.PublicKeyPEM)
103109
}
104110

105111
func TestIgnition_getRendezvousHostEnv(t *testing.T) {
@@ -657,6 +663,7 @@ func buildIgnitionAssetDefaultDependencies(t *testing.T) []asset.Asset {
657663
&tls.KubeAPIServerServiceNetworkSignerCertKey{},
658664
&tls.AdminKubeConfigSignerCertKey{},
659665
&tls.AdminKubeConfigClientCertKey{},
666+
&gencrypto.AuthConfig{},
660667
}
661668
}
662669

0 commit comments

Comments
 (0)