Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Hepto
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
ACIDES
Hepto
Commits
bea82082
Commit
bea82082
authored
2 years ago
by
kaiyou
Browse files
Options
Downloads
Patches
Plain Diff
Use the new PKI API to generate node certificates
parent
7f3b4654
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Pipeline
#21052
passed
2 years ago
Stage: build
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
pkg/cluster/cluster.go
+18
-51
18 additions, 51 deletions
pkg/cluster/cluster.go
pkg/cluster/meta.go
+60
-12
60 additions, 12 deletions
pkg/cluster/meta.go
pkg/cluster/pki.go
+84
-12
84 additions, 12 deletions
pkg/cluster/pki.go
with
162 additions
and
75 deletions
pkg/cluster/cluster.go
+
18
−
51
View file @
bea82082
...
...
@@ -5,7 +5,6 @@ package cluster
import
(
"net"
"forge.tedomum.net/acides/hepto/hepto/pkg/pki"
"forge.tedomum.net/acides/hepto/hepto/pkg/sml"
"forge.tedomum.net/acides/hepto/hepto/pkg/wg"
"github.com/sirupsen/logrus"
...
...
@@ -13,7 +12,7 @@ import (
type
Cluster
struct
{
settings
*
ClusterSettings
ml
*
sml
.
Memberlist
[
HeptoMeta
,
*
HeptoMeta
]
ml
*
sml
.
Memberlist
[
HeptoMeta
,
HeptoState
,
*
HeptoMeta
,
*
HeptoState
]
vpn
*
wg
.
Wireguard
networking
*
ClusterNetworking
node
*
NodeSettings
...
...
@@ -28,7 +27,7 @@ func New(settings *ClusterSettings, node *NodeSettings) (*Cluster, error) {
networking
:
NewClusterNetworking
(
settings
.
Name
,
node
.
Name
),
}
// Prepare memberlist
c
.
ml
=
sml
.
New
[
HeptoMeta
](
node
.
Name
,
node
.
IP
,
node
.
Port
,
node
.
Anchors
,
settings
.
Key
)
c
.
ml
=
sml
.
New
[
HeptoMeta
,
HeptoState
](
node
.
Name
,
node
.
IP
,
node
.
Port
,
node
.
Anchors
,
settings
.
Key
)
// Prepare wireguard
vpn
,
err
:=
wg
.
New
(
"wg0"
,
7124
,
c
.
networking
.
NodeAddress
.
IPNet
())
if
err
!=
nil
{
...
...
@@ -42,18 +41,21 @@ func New(settings *ClusterSettings, node *NodeSettings) (*Cluster, error) {
return
nil
,
err
}
c
.
pki
=
pki
}
else
{
c
.
pki
=
&
ClusterPKI
{}
}
certs
,
err
:=
NewNodeCerts
(
"certs"
,
node
.
Name
)
if
err
!=
nil
{
return
nil
,
err
}
c
.
certs
=
certs
// Initialize cluster meta
meta
:=
c
.
ml
.
Meta
meta
.
VpnKey
=
vpn
.
PubKey
.
String
()
meta
.
Role
=
node
.
Role
meta
.
Certs
=
make
(
map
[
string
]
NodePKIBytes
)
meta
.
CSR
.
APIClient
=
certs
.
APIClient
.
CSR
// Initialize node meta
c
.
ml
.
Meta
.
VpnKey
=
vpn
.
PubKey
.
String
()
c
.
ml
.
Meta
.
Role
=
node
.
Role
// Initialize cluster state
c
.
ml
.
State
.
PKI
=
c
.
pki
c
.
ml
.
State
.
Certificates
=
make
(
map
[
string
]
*
NodeCerts
)
c
.
ml
.
State
.
Certificates
[
node
.
Name
]
=
certs
return
c
,
nil
}
...
...
@@ -69,7 +71,9 @@ func (c *Cluster) Run() error {
for
{
select
{
case
<-
events
:
c
.
handlePKI
()
if
c
.
node
.
Role
==
"master"
{
c
.
handlePKI
()
}
c
.
updateVPN
()
case
<-
instrUpdates
:
c
.
networking
.
MTU
=
instr
.
MinMTU
()
...
...
@@ -79,45 +83,8 @@ func (c *Cluster) Run() error {
}
func
(
c
*
Cluster
)
handlePKI
()
{
logrus
.
Debug
(
"handling possible PKI messages"
)
for
_
,
node
:=
range
c
.
ml
.
Nodes
()
{
meta
:=
node
.
NodeMeta
if
meta
.
Role
==
"master"
{
logrus
.
Debug
(
"found master node, checking certs"
)
logrus
.
Debug
(
string
(
node
.
Meta
))
if
certs
,
ok
:=
meta
.
Certs
[
c
.
node
.
Name
];
ok
{
if
len
(
certs
.
APIClient
)
>
0
{
logrus
.
Debug
(
"certificate is signed"
)
err
:=
c
.
certs
.
APIClient
.
SetCert
(
certs
.
APIClient
)
if
err
!=
nil
{
logrus
.
Warn
(
"cannot load certificate"
)
}
}
}
}
}
if
c
.
pki
!=
nil
{
logrus
.
Debug
(
"this is the master, generating required certificates"
)
for
_
,
node
:=
range
c
.
ml
.
Nodes
()
{
meta
:=
node
.
NodeMeta
if
len
(
meta
.
CSR
.
APIClient
)
>
0
{
template
:=
pki
.
NewClientTemplate
(
node
.
Name
,
""
)
cert
,
err
:=
c
.
pki
.
APIServer
.
Sign
(
meta
.
CSR
.
APIClient
,
template
)
if
err
!=
nil
{
logrus
.
Warn
(
"cannot sign certificate"
)
continue
}
logrus
.
Debug
(
"signed for "
,
node
.
Name
,
cert
)
this
:=
c
.
ml
.
Meta
var
certs
NodePKIBytes
if
certs
,
ok
:=
this
.
Certs
[
node
.
Name
];
!
ok
{
this
.
Certs
[
node
.
Name
]
=
certs
}
certs
.
APIClient
=
cert
this
.
Certs
[
node
.
Name
]
=
certs
c
.
ml
.
Update
()
}
}
for
name
,
certs
:=
range
c
.
ml
.
State
.
Certificates
{
c
.
pki
.
SignNodeCerts
(
name
,
certs
)
}
}
...
...
@@ -131,12 +98,12 @@ func (c *Cluster) updateVPN() {
peerAddr
:=
c
.
networking
.
NodeNet
.
DeriveAddress
(
node
.
Name
)
.
IP
peer
,
err
:=
c
.
vpn
.
MakePeer
(
node
.
Addr
,
meta
.
VpnKey
,
peerAddr
,
[]
net
.
IPNet
{})
if
err
!=
nil
{
logrus
.
Debug
(
"
C
annot setup VPN with node "
,
node
.
Name
)
logrus
.
Debug
(
"
c
annot setup VPN with node "
,
node
.
Name
)
logrus
.
Debug
(
err
)
continue
}
peers
=
append
(
peers
,
peer
)
}
logrus
.
Debugf
(
"
U
pdating
the
VPN mesh
with
%d peers, MTU %d"
,
len
(
peers
),
c
.
networking
.
MTU
)
logrus
.
Debugf
(
"
u
pdating VPN mesh
,
%d peers, MTU %d"
,
len
(
peers
),
c
.
networking
.
MTU
)
c
.
vpn
.
Update
(
peers
,
c
.
networking
.
MTU
)
}
This diff is collapsed.
Click to expand it.
pkg/cluster/meta.go
+
60
−
12
View file @
bea82082
...
...
@@ -2,34 +2,82 @@ package cluster
import
(
"encoding/json"
"fmt"
"strings"
)
// Represents a node CSRs and returned certs
type
NodePKIBytes
struct
{
// APIclient certificate
APIClient
[]
byte
`json:"apiclient"`
}
// Represents a node metadata
type
HeptoMeta
struct
{
// Public key for the wireguard mesh VPN
VpnKey
string
`json:"vpnKey"`
// Node role inside the cluster
Role
string
`json:"role"`
// Certificate CSRs
CSR
NodePKIBytes
`json:"csr"`
// Only on master, signed certificates
Certs
map
[
string
]
NodePKIBytes
`json:"certs"`
}
// Represents the cluster state
type
HeptoState
struct
{
// Cluster CAs public certificates
PKI
*
ClusterPKI
`json:"ca"`
// Certificate per node, this should only
// be updated by the node itself
Certificates
map
[
string
]
*
NodeCerts
`json:"nodes"`
}
func
(
m
*
HeptoMeta
)
Encode
()
([]
byte
,
error
)
{
return
json
.
Marshal
(
&
m
)
return
json
.
Marshal
(
m
)
}
func
(
m
*
HeptoMeta
)
Decode
(
b
[]
byte
)
error
{
return
json
.
Unmarshal
(
b
,
&
m
)
return
json
.
Unmarshal
(
b
,
m
)
}
func
(
m
*
HeptoMeta
)
String
()
string
{
return
m
.
Role
}
func
(
s
*
HeptoState
)
Encode
()
([]
byte
,
error
)
{
return
json
.
Marshal
(
s
)
}
func
(
s
*
HeptoState
)
Decode
(
b
[]
byte
)
error
{
return
json
.
Unmarshal
(
b
,
s
)
}
func
(
s
*
HeptoState
)
String
()
string
{
var
res
string
if
s
.
PKI
!=
nil
{
var
ca
[]
string
if
s
.
PKI
.
API
!=
nil
{
ca
=
append
(
ca
,
"api"
)
}
if
s
.
PKI
.
Kubelet
!=
nil
{
ca
=
append
(
ca
,
"kubelet"
)
}
if
s
.
PKI
.
Services
!=
nil
{
ca
=
append
(
ca
,
"services"
)
}
res
+=
fmt
.
Sprintf
(
"ca{%s}"
,
strings
.
Join
(
ca
,
", "
))
}
return
res
}
func
(
s
*
HeptoState
)
Merge
(
b
[]
byte
)
error
{
remote
:=
new
(
HeptoState
)
err
:=
json
.
Unmarshal
(
b
,
remote
)
if
err
!=
nil
{
return
err
}
if
remote
.
PKI
==
nil
{
return
nil
}
s
.
PKI
.
Merge
(
remote
.
PKI
)
for
name
,
remoteCerts
:=
range
remote
.
Certificates
{
_
,
ok
:=
s
.
Certificates
[
name
]
if
ok
{
s
.
Certificates
[
name
]
.
Merge
(
remoteCerts
)
}
else
{
s
.
Certificates
[
name
]
=
remoteCerts
}
}
return
nil
}
This diff is collapsed.
Click to expand it.
pkg/cluster/pki.go
+
84
−
12
View file @
bea82082
package
cluster
import
(
"crypto/x509"
"os"
"path/filepath"
"forge.tedomum.net/acides/hepto/hepto/pkg/pki"
"github.com/sirupsen/logrus"
)
// Cluster PKI is made of three different PKIs
type
ClusterPKI
struct
{
Services
*
pki
.
CA
Kubelet
*
pki
.
CA
APIServer
*
pki
.
CA
// Signs services exposed over the cluster
Services
*
pki
.
PKI
`json:"services"`
// Signs kubelet client certificates (master)
Kubelet
*
pki
.
PKI
`json:"kubelet"`
// Signs apiserver client certificates (nodes and controller)
API
*
pki
.
PKI
`json:"api"`
}
// Node certs
type
NodeCerts
struct
{
// Certificate for exposing the kubelet service
Service
*
pki
.
Certificate
`json:"service"`
// Node certificate for accessing the apiserver
API
*
pki
.
Certificate
`json:"api"`
}
// Merge PKI
func
(
n
*
ClusterPKI
)
Merge
(
other
*
ClusterPKI
)
{
if
other
.
API
!=
nil
{
n
.
API
=
other
.
API
}
if
other
.
Services
!=
nil
{
n
.
Services
=
other
.
Services
}
if
other
.
Kubelet
!=
nil
{
n
.
Kubelet
=
other
.
Kubelet
}
}
// Merge a single node certificate
func
mergeNodeCert
(
local
*
pki
.
Certificate
,
remote
*
pki
.
Certificate
)
{
// Import CSR to master for signing
if
remote
.
CSR
!=
nil
{
local
.
CSR
=
remote
.
CSR
}
// Import and save cert back to node
if
remote
.
Cert
!=
nil
{
local
.
Cert
=
remote
.
Cert
local
.
Save
()
}
}
// Merge node certificates
func
(
n
*
NodeCerts
)
Merge
(
other
*
NodeCerts
)
{
mergeNodeCert
(
n
.
Service
,
other
.
Service
)
mergeNodeCert
(
n
.
API
,
other
.
API
)
}
func
NewClusterPKI
(
path
string
)
(
*
ClusterPKI
,
error
)
{
...
...
@@ -18,35 +64,61 @@ func NewClusterPKI(path string) (*ClusterPKI, error) {
if
err
!=
nil
{
return
nil
,
err
}
servicesCA
,
err
:=
pki
.
Get
CA
(
filepath
.
Join
(
path
,
"services"
))
servicesCA
,
err
:=
pki
.
Get
PKI
(
filepath
.
Join
(
path
,
"services"
))
if
err
!=
nil
{
return
nil
,
err
}
kubeletCA
,
err
:=
pki
.
Get
CA
(
filepath
.
Join
(
path
,
"kubelet"
))
kubeletCA
,
err
:=
pki
.
Get
PKI
(
filepath
.
Join
(
path
,
"kubelet"
))
if
err
!=
nil
{
return
nil
,
err
}
apiserverCA
,
err
:=
pki
.
Get
CA
(
filepath
.
Join
(
path
,
"api
server
"
))
apiserverCA
,
err
:=
pki
.
Get
PKI
(
filepath
.
Join
(
path
,
"api"
))
if
err
!=
nil
{
return
nil
,
err
}
return
&
ClusterPKI
{
servicesCA
,
kubeletCA
,
apiserverCA
},
nil
}
type
NodeCerts
struct
{
APIClient
*
pki
.
CertKey
}
func
NewNodeCerts
(
path
string
,
nodeName
string
)
(
*
NodeCerts
,
error
)
{
err
:=
os
.
MkdirAll
(
path
,
0755
)
if
err
!=
nil
{
return
nil
,
err
}
apiClientCert
,
err
:=
pki
.
LoadWithCSR
(
filepath
.
Join
(
path
,
"apiclient"
),
pki
.
NewClientTemplate
(
nodeName
,
""
))
// Service certificate
serviceCert
,
err
:=
pki
.
GetCertificate
(
filepath
.
Join
(
path
,
"service"
))
if
err
!=
nil
{
return
nil
,
err
}
err
=
serviceCert
.
MakeCSR
(
pki
.
NewServerTemplate
([]
string
{
nodeName
}))
if
err
!=
nil
{
return
nil
,
err
}
// API certificate
apiClientCert
,
err
:=
pki
.
GetCertificate
(
filepath
.
Join
(
path
,
"api"
))
if
err
!=
nil
{
return
nil
,
err
}
err
=
apiClientCert
.
MakeCSR
(
pki
.
NewClientTemplate
(
nodeName
,
""
))
if
err
!=
nil
{
return
nil
,
err
}
return
&
NodeCerts
{
APIClient
:
apiClientCert
,
Service
:
serviceCert
,
API
:
apiClientCert
,
},
nil
}
func
signCert
(
p
*
pki
.
PKI
,
c
*
pki
.
Certificate
,
template
*
x509
.
Certificate
)
{
if
c
.
CSR
!=
nil
&&
c
.
Cert
==
nil
{
logrus
.
Info
(
"signing certificate "
,
c
.
CSR
.
Subject
.
String
())
err
:=
p
.
Sign
(
c
,
template
)
if
err
!=
nil
{
logrus
.
Warnf
(
"cannot sign API certificate for %s: %s"
,
c
.
CSR
.
Subject
.
String
(),
err
)
}
}
}
func
(
p
*
ClusterPKI
)
SignNodeCerts
(
name
string
,
n
*
NodeCerts
)
{
signCert
(
p
.
Services
,
n
.
Service
,
pki
.
NewServerTemplate
([]
string
{
name
}))
signCert
(
p
.
API
,
n
.
API
,
pki
.
NewClientTemplate
(
name
,
""
))
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment