forked from juju/juju
-
Notifications
You must be signed in to change notification settings - Fork 0
/
manifold.go
139 lines (116 loc) · 3.32 KB
/
manifold.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2017 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package apiservercertwatcher
import (
"github.com/juju/errors"
"github.com/juju/worker/v3"
"github.com/juju/worker/v3/dependency"
"gopkg.in/tomb.v2"
"github.com/DavinZhang/juju/agent"
"github.com/DavinZhang/juju/pki"
)
type AuthorityWorker interface {
Authority() pki.Authority
worker.Worker
}
type NewCertWatcherWorker func(agent.Agent) (AuthorityWorker, error)
type ManifoldConfig struct {
AgentName string
CertWatcherWorkerFn NewCertWatcherWorker
}
// The manifold is intended to be a dependency for the apiserver.
// Manifold provides a worker for supplying a pki Authority to other workers
// that want to create and modify certificates in a Juju controller.
func Manifold(config ManifoldConfig) dependency.Manifold {
return dependency.Manifold{
Inputs: []string{config.AgentName},
Start: func(context dependency.Context) (worker.Worker, error) {
var a agent.Agent
if err := context.Get(config.AgentName, &a); err != nil {
return nil, err
}
if config.CertWatcherWorkerFn != nil {
return config.CertWatcherWorkerFn(a)
}
w := &apiserverCertWatcher{
agent: a,
}
if err := w.setup(); err != nil {
return nil, errors.Annotate(err, "setting up initial ca authority")
}
w.tomb.Go(w.loop)
return w, nil
},
Output: outputFunc,
}
}
func outputFunc(in worker.Worker, out interface{}) error {
inWorker, _ := in.(AuthorityWorker)
if inWorker == nil {
return errors.Errorf("in should be a %T; got a %T", inWorker, in)
}
switch result := out.(type) {
case *pki.Authority:
*result = inWorker.Authority()
default:
return errors.Errorf("unexpected type")
}
return nil
}
type apiserverCertWatcher struct {
tomb tomb.Tomb
agent agent.Agent
authority pki.Authority
}
func (w *apiserverCertWatcher) loop() error {
select {
case <-w.tomb.Dying():
return tomb.ErrDying
}
}
func (w *apiserverCertWatcher) Authority() pki.Authority {
return w.authority
}
// Kill implements worker.Worker.
func (w *apiserverCertWatcher) Kill() {
w.tomb.Kill(nil)
}
func (w *apiserverCertWatcher) setup() error {
config := w.agent.CurrentConfig()
info, ok := config.StateServingInfo()
if !ok {
return errors.New("no state serving info in agent config")
}
caCert := config.CACert()
if caCert == "" {
return errors.New("no ca certificate found in config")
}
caPrivateKey := info.CAPrivateKey
if caPrivateKey == "" {
return errors.New("no CA cert private key")
}
authority, err := pki.NewDefaultAuthorityPemCAKey([]byte(caCert),
[]byte(caPrivateKey))
if err != nil {
return errors.Annotate(err, "building authority from pem ca")
}
_, err = authority.LeafGroupFromPemCertKey(pki.DefaultLeafGroup,
[]byte(info.Cert), []byte(info.PrivateKey))
if err != nil {
return errors.Annotate(err, "loading default certificate for controller")
}
_, signers, err := pki.UnmarshalPemData([]byte(info.PrivateKey))
if err != nil {
return errors.Annotate(err, "setting default certificate signing key")
}
if len(signers) != 1 {
return errors.Annotate(err, "expected one signing key from certificate pem data")
}
authority.SetLeafSigner(signers[0])
w.authority = authority
return nil
}
// Wait implements worker.Worker.
func (w *apiserverCertWatcher) Wait() error {
return w.tomb.Wait()
}