Skip to content

Commit facd292

Browse files
authored
Merge pull request #69 from RobotSail/secret-update
Create Unique Identities for IPFS Containers
2 parents e557169 + e2f5cb1 commit facd292

File tree

4 files changed

+112
-22
lines changed

4 files changed

+112
-22
lines changed

controllers/ipfs_controller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,10 @@ func (r *IpfsReconciler) createTrackedObjects(
143143

144144
mutsa := r.serviceAccount(instance, &sa)
145145
mutsvc, svcName := r.serviceCluster(instance, &svc)
146+
146147
mutCmScripts, cmScriptName := r.ConfigMapScripts(ctx, instance, &cmScripts)
148+
mutSecConfig, secConfigName := r.secretConfig(ctx, instance, &secConfig, []byte(clusterSecret), []byte(privateString))
147149
mutCmConfig, cmConfigName := r.configMapConfig(instance, &cmConfig, peerID.String())
148-
mutSecConfig, secConfigName := r.secretConfig(instance, &secConfig, []byte(clusterSecret), []byte(privateString))
149150
mutSts := r.statefulSet(instance, &sts, svcName, secConfigName, cmConfigName, cmScriptName)
150151

151152
trackedObjects := map[client.Object]controllerutil.MutateFn{

controllers/scripts/config.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ import (
55
"encoding/json"
66
"fmt"
77
"math"
8-
"os"
98
"strconv"
109
"text/template"
1110

1211
"github.com/alecthomas/units"
13-
"github.com/ipfs/interface-go-ipfs-core/options"
1412
"github.com/ipfs/kubo/config"
1513
"github.com/libp2p/go-libp2p-core/peer"
1614
)
@@ -28,6 +26,11 @@ user=ipfs
2826
# This is a custom entrypoint for k8s designed to run ipfs nodes in an appropriate
2927
# setup for production scenarios.
3028
29+
INDEX="${HOSTNAME##*-}"
30+
31+
PRIVATE_KEY=$(cat "/node-data/privateKey-${INDEX}")
32+
PEER_ID=$(cat "/node-data/peerID-${INDEX}")
33+
3134
if [[ -f /data/ipfs/config ]]; then
3235
if [[ -f /data/ipfs/repo.lock ]]; then
3336
rm /data/ipfs/repo.lock
@@ -36,6 +39,9 @@ if [[ -f /data/ipfs/config ]]; then
3639
fi
3740
3841
echo '{{ .FlattenedConfig }}' > config.json
42+
sed -i s,_peer-id_,"${PEER_ID}",g config.json
43+
sed -i s,_private-key_,"${PRIVATE_KEY}",g config.json
44+
3945
ipfs init -- config.json
4046
4147
chown -R ipfs: /data/ipfs
@@ -182,7 +188,7 @@ func applyFlatfsServer(conf *config.Config) error {
182188

183189
// setFlatfsShardFunc Attempts to update the given flatfs configuration to use a shardFunc
184190
// with the given `n`. If unsuccessful, false will be returned.
185-
func setFlatfsShardFunc(conf *config.Config, n uint8) error {
191+
func setFlatfsShardFunc(conf *config.Config, n int8) error {
186192
// we want to use next-to-last/3 as the sharding function
187193
// as per this issue:
188194
// https://github.com/redhat-et/ipfs-operator/issues/32
@@ -210,7 +216,7 @@ func setFlatfsShardFunc(conf *config.Config, n uint8) error {
210216
continue
211217
}
212218
if dsType == "flatfs" {
213-
child["shardFunc"] = "/repo/flatfs/shard/v1/next-to-last/" + strconv.FormatUint(uint64(n), 10)
219+
child["shardFunc"] = "/repo/flatfs/shard/v1/next-to-last/" + strconv.FormatInt(int64(n), 10)
214220
break
215221
}
216222
}
@@ -241,17 +247,10 @@ func createTemplateConfig(
241247
rc config.RelayClient,
242248
) (conf config.Config, err error) {
243249
// attempt to generate an identity
244-
var identity config.Identity
245250

246-
// try to generate an elliptic curve key first
247-
identity, err = config.CreateIdentity(os.Stdout, []options.KeyGenerateOption{
248-
options.Key.Type(options.Ed25519Key),
249-
})
250-
if err != nil {
251-
return
252-
}
253251
// set keys + defaults
254-
conf.Identity = identity
252+
conf.Identity.PeerID = "_peer-id_"
253+
conf.Identity.PrivKey = "_private-key_"
255254

256255
// apply the server + flatfs profiles
257256
if err = applyFlatfsServer(&conf); err != nil {

controllers/secret.go

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,115 @@
11
package controllers
22

33
import (
4+
"context"
5+
"strconv"
6+
"strings"
7+
48
corev1 "k8s.io/api/core/v1"
9+
"k8s.io/apimachinery/pkg/api/errors"
510
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
611
ctrl "sigs.k8s.io/controller-runtime"
12+
"sigs.k8s.io/controller-runtime/pkg/client"
713
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
814

915
clusterv1alpha1 "github.com/redhat-et/ipfs-operator/api/v1alpha1"
1016
)
1117

18+
const (
19+
peerIDPrefix = "peerID-"
20+
privateKeyPrefix = "privateKey-"
21+
)
22+
23+
// errorFunc Returns a function which returns the provided
24+
// error when it is called.
25+
func errorFunc(err error) controllerutil.MutateFn {
26+
return func() error {
27+
return err
28+
}
29+
}
30+
1231
func (r *IpfsReconciler) secretConfig(
32+
ctx context.Context,
1333
m *clusterv1alpha1.Ipfs,
1434
sec *corev1.Secret,
1535
clusterSecret,
1636
bootstrapPrivateKey []byte,
1737
) (controllerutil.MutateFn, string) {
1838
secName := "ipfs-cluster-" + m.Name
19-
expected := &corev1.Secret{
39+
40+
expectedSecret := &corev1.Secret{
2041
ObjectMeta: metav1.ObjectMeta{
2142
Name: secName,
2243
Namespace: m.Namespace,
2344
},
24-
Data: map[string][]byte{
25-
"CLUSTER_SECRET": clusterSecret,
26-
"BOOTSTRAP_PEER_PRIV_KEY": bootstrapPrivateKey,
27-
},
2845
}
29-
expected.DeepCopyInto(sec)
46+
// find secret
47+
err := r.Get(ctx, client.ObjectKeyFromObject(expectedSecret), expectedSecret)
48+
if err != nil && !errors.IsNotFound(err) {
49+
return errorFunc(err), ""
50+
}
51+
// initialize the secret, if needed
52+
if err != nil && errors.IsNotFound(err) {
53+
expectedSecret.Data = make(map[string][]byte, 0)
54+
expectedSecret.StringData = make(map[string]string, 0)
55+
// secret doesn't exist
56+
err = generateNewIdentities(expectedSecret, 0, m.Spec.Replicas)
57+
if err != nil {
58+
return errorFunc(err), ""
59+
}
60+
expectedSecret.Data["CLUSTER_SECRET"] = clusterSecret
61+
expectedSecret.Data["BOOTSTRAP_PEER_PRIV_KEY"] = bootstrapPrivateKey
62+
}
63+
64+
// secret does exist
65+
numIdentities := countIdentities(expectedSecret)
66+
if numIdentities != m.Spec.Replicas {
67+
// create more identities if needed, otherwise they will be reused
68+
// when scaling down and then up again
69+
if numIdentities < m.Spec.Replicas {
70+
// create more
71+
err = generateNewIdentities(expectedSecret, numIdentities, m.Spec.Replicas)
72+
if err != nil {
73+
return errorFunc(err), ""
74+
}
75+
}
76+
}
77+
78+
expectedSecret.DeepCopyInto(sec)
3079
// FIXME: catch this error before we run the function being returned
31-
if err := ctrl.SetControllerReference(m, sec, r.Scheme); err != nil {
32-
return func() error { return err }, ""
80+
if err = ctrl.SetControllerReference(m, sec, r.Scheme); err != nil {
81+
return errorFunc(err), ""
3382
}
3483
return func() error {
84+
sec.Data = expectedSecret.Data
3585
return nil
3686
}, secName
3787
}
88+
89+
// countIdentities Counts the amount of unique peer identities present in the secret.
90+
func countIdentities(secret *corev1.Secret) int32 {
91+
var count int32
92+
for key := range secret.Data {
93+
if strings.Contains(key, peerIDPrefix) {
94+
count++
95+
}
96+
}
97+
return count
98+
}
99+
100+
// generateNewIdentities Populates the secret data with new Peer IDs
101+
// and private keys which are mapped based on the replica number.
102+
func generateNewIdentities(secret *corev1.Secret, start, n int32) error {
103+
for i := start; i < n; i++ {
104+
// generate new private key & peer id
105+
peerID, privKey, err := generateIdentity()
106+
if err != nil {
107+
return err
108+
}
109+
peerIDKey := peerIDPrefix + strconv.Itoa(int(i))
110+
secret.StringData[peerIDKey] = peerID.String()
111+
secretKey := privateKeyPrefix + strconv.Itoa(int(i))
112+
secret.StringData[secretKey] = privKey
113+
}
114+
return nil
115+
}

controllers/statefulset.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ func (r *IpfsReconciler) statefulSet(m *clusterv1alpha1.Ipfs,
101101
Name: "configure-script",
102102
MountPath: "custom",
103103
},
104+
{
105+
Name: "ipfs-node-data",
106+
MountPath: "/node-data",
107+
},
104108
},
105109
},
106110
},
@@ -265,6 +269,14 @@ func (r *IpfsReconciler) statefulSet(m *clusterv1alpha1.Ipfs,
265269
},
266270
},
267271
},
272+
{
273+
Name: "ipfs-node-data",
274+
VolumeSource: corev1.VolumeSource{
275+
Secret: &corev1.SecretVolumeSource{
276+
SecretName: secretName,
277+
},
278+
},
279+
},
268280
},
269281
},
270282
},

0 commit comments

Comments
 (0)