1
16
17 package writer
18
19 import (
20 "errors"
21 "fmt"
22 "io/ioutil"
23 "os"
24 "path"
25
26 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/generator"
27 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/writer/atomic"
28
29 "sigs.k8s.io/controller-runtime/pkg/client"
30 )
31
32
33 type fsCertWriter struct {
34
35 dnsName string
36
37 *FSCertWriterOptions
38 }
39
40
41 type FSCertWriterOptions struct {
42
43 CertGenerator generator.CertGenerator
44
45 Path string
46 }
47
48 var _ CertWriter = &fsCertWriter{}
49
50 func (ops *FSCertWriterOptions) setDefaults() {
51 if ops.CertGenerator == nil {
52 ops.CertGenerator = &generator.SelfSignedCertGenerator{}
53 }
54 }
55
56 func (ops *FSCertWriterOptions) validate() error {
57 if len(ops.Path) == 0 {
58 return errors.New("path must be set in FSCertWriterOptions")
59 }
60 return nil
61 }
62
63
64 func NewFSCertWriter(ops FSCertWriterOptions) (CertWriter, error) {
65 ops.setDefaults()
66 err := ops.validate()
67 if err != nil {
68 return nil, err
69 }
70 return &fsCertWriter{
71 FSCertWriterOptions: &ops,
72 }, nil
73 }
74
75
76 func (f *fsCertWriter) EnsureCert(dnsName string) (*generator.Artifacts, bool, error) {
77
78 f.dnsName = dnsName
79 return handleCommon(f.dnsName, f)
80 }
81
82 func (f *fsCertWriter) write() (*generator.Artifacts, error) {
83 return f.doWrite()
84 }
85
86 func (f *fsCertWriter) overwrite() (*generator.Artifacts, error) {
87 return f.doWrite()
88 }
89
90 func (f *fsCertWriter) doWrite() (*generator.Artifacts, error) {
91 certs, err := f.CertGenerator.Generate(f.dnsName)
92 if err != nil {
93 return nil, err
94 }
95
96
97
98
99 err = prepareToWrite(f.Path)
100 if err != nil {
101 return nil, err
102 }
103
104 aw, err := atomic.NewAtomicWriter(f.Path, log.WithName("atomic-writer").
105 WithValues("task", "processing webhook"))
106 if err != nil {
107 return nil, err
108 }
109 err = aw.Write(certToProjectionMap(certs))
110 return certs, err
111 }
112
113
114 func prepareToWrite(dir string) error {
115 _, err := os.Stat(dir)
116 switch {
117 case os.IsNotExist(err):
118 log.Info("cert directory doesn't exist, creating", "directory", dir)
119
120 err = os.MkdirAll(dir, 0777)
121 if err != nil {
122 return fmt.Errorf("can't create dir: %v", dir)
123 }
124 case err != nil:
125 return err
126 }
127
128 filenames := []string{CAKeyName, CACertName, ServerCertName, ServerKeyName}
129 for _, f := range filenames {
130 abspath := path.Join(dir, f)
131 _, err := os.Stat(abspath)
132 if os.IsNotExist(err) {
133 continue
134 } else if err != nil {
135 log.Error(err, "unable to stat file", "file", abspath)
136 }
137 _, err = os.Readlink(abspath)
138
139 if err != nil {
140 err = os.Remove(abspath)
141 if err != nil {
142 log.Error(err, "unable to remove old file", "file", abspath)
143 }
144 }
145 }
146 return nil
147 }
148
149 func (f *fsCertWriter) read() (*generator.Artifacts, error) {
150 if err := ensureExist(f.Path); err != nil {
151 return nil, err
152 }
153 caKeyBytes, err := ioutil.ReadFile(path.Join(f.Path, CAKeyName))
154 if err != nil {
155 return nil, err
156 }
157 caCertBytes, err := ioutil.ReadFile(path.Join(f.Path, CACertName))
158 if err != nil {
159 return nil, err
160 }
161 certBytes, err := ioutil.ReadFile(path.Join(f.Path, ServerCertName))
162 if err != nil {
163 return nil, err
164 }
165 keyBytes, err := ioutil.ReadFile(path.Join(f.Path, ServerKeyName))
166 if err != nil {
167 return nil, err
168 }
169 return &generator.Artifacts{
170 CAKey: caKeyBytes,
171 CACert: caCertBytes,
172 Cert: certBytes,
173 Key: keyBytes,
174 }, nil
175 }
176
177 func ensureExist(dir string) error {
178 filenames := []string{CAKeyName, CACertName, ServerCertName, ServerKeyName}
179 for _, filename := range filenames {
180 _, err := os.Stat(path.Join(dir, filename))
181 switch {
182 case err == nil:
183 continue
184 case os.IsNotExist(err):
185 return notFoundError{err}
186 default:
187 return err
188 }
189 }
190 return nil
191 }
192
193 func certToProjectionMap(cert *generator.Artifacts) map[string]atomic.FileProjection {
194
195 return map[string]atomic.FileProjection{
196 CAKeyName: {
197 Data: cert.CAKey,
198 Mode: 0666,
199 },
200 CACertName: {
201 Data: cert.CACert,
202 Mode: 0666,
203 },
204 ServerCertName: {
205 Data: cert.Cert,
206 Mode: 0666,
207 },
208 ServerKeyName: {
209 Data: cert.Key,
210 Mode: 0666,
211 },
212 }
213 }
214
215 func (f *fsCertWriter) Inject(objs ...client.Object) error {
216 return nil
217 }
218
View as plain text