Skip to content

Commit 5741774

Browse files
AshishNawaregeofffranks
authored andcommitted
fix: add special-case flag to store certs when frontend_tls configuration includes certificate entries
1 parent 9aa35d9 commit 5741774

File tree

5 files changed

+49
-64
lines changed

5 files changed

+49
-64
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/bash -e
22

33
<% if spec.bootstrap == true %>
4-
/var/vcap/packages/tcp_router/bin/config-validator -config /var/vcap/jobs/tcp_router/config/tcp_router.yml
4+
/var/vcap/packages/tcp_router/bin/config-validator -config /var/vcap/jobs/tcp_router/config/tcp_router.yml -enable-cert-creation true
55
<% end %>

src/code.cloudfoundry.org/cf-tcp-router/cmd/cf-tcp-router/main.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ var configFile = flag.String(
7676
"The Router configurer yml config.",
7777
)
7878

79+
var enableCertCreation = flag.Bool(
80+
"enable-cert-creation",
81+
false,
82+
"Parse certs and keys from tcp_router.yml and store them",
83+
)
84+
7985
var routingGroupCheckExit = flag.Bool(
8086
"routingGroupCheckExit",
8187
false,
@@ -152,7 +158,7 @@ func main() {
152158

153159
initializeDropsonde(logger)
154160

155-
cfg, err := config.New(*configFile)
161+
cfg, err := config.New(*configFile, *enableCertCreation)
156162
if err != nil {
157163
logger.Error("failed-to-unmarshal-config-file", err)
158164
os.Exit(1)

src/code.cloudfoundry.org/cf-tcp-router/cmd/config-validator/main.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@ import (
88
)
99

1010
var (
11-
configFile string
11+
configFile string
12+
enableCertCreation bool
1213
)
1314

1415
func main() {
1516
flag.StringVar(&configFile, "config", "", "Configuration File")
17+
18+
// enableCertCreation is a special-case flag that allows the TCP router to generate
19+
// certificates and keys when frontend_tls certificates are defined in tcp_router.yml
20+
flag.BoolVar(&enableCertCreation, "enable-cert-creation", false, "Enables creation certs and keys")
1621
flag.Parse()
1722

18-
_, err := config.New(configFile)
23+
_, err := config.New(configFile, enableCertCreation)
1924
if err != nil {
2025
log.Fatal("failed-to-load-config: ", err)
2126
}

src/code.cloudfoundry.org/cf-tcp-router/config/config.go

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"path/filepath"
1313
"strconv"
1414
"strings"
15-
"syscall"
1615
"time"
1716

1817
"gopkg.in/yaml.v3"
@@ -70,9 +69,9 @@ type Config struct {
7069

7170
const DrainWaitDefault = 20 * time.Second
7271

73-
func New(path string) (*Config, error) {
72+
func New(path string, enableCertCreation bool) (*Config, error) {
7473
c := &Config{}
75-
err := c.initConfigFromFile(path)
74+
err := c.initConfigFromFile(path, enableCertCreation)
7675
if err != nil {
7776
return nil, err
7877
}
@@ -103,7 +102,7 @@ func resolveGroupID(primary, fallback string) (int, error) {
103102
return gid, nil
104103
}
105104

106-
func (c *Config) initConfigFromFile(path string) error {
105+
func (c *Config) initConfigFromFile(path string, enableCertCreation bool) error {
107106
b, err := os.ReadFile(path)
108107
if err != nil {
109108
return err
@@ -121,22 +120,21 @@ func (c *Config) initConfigFromFile(path string) error {
121120
c.DrainWaitDuration = DrainWaitDefault
122121
}
123122

124-
owner, err := user.Lookup("root")
125-
if err != nil {
126-
return err
127-
}
128-
129-
uid, err := strconv.Atoi(owner.Uid)
130-
if err != nil {
131-
return err
132-
}
123+
if enableCertCreation && len(c.FrontendTLSJob) > 0 {
124+
owner, err := user.Lookup("root")
125+
if err != nil {
126+
return err
127+
}
133128

134-
gid, err := resolveGroupID("vcap", "root")
135-
if err != nil {
136-
return err
137-
}
129+
uid, err := strconv.Atoi(owner.Uid)
130+
if err != nil {
131+
return err
132+
}
138133

139-
if len(c.FrontendTLSJob) > 0 {
134+
gid, err := resolveGroupID("vcap", "root")
135+
if err != nil {
136+
return err
137+
}
140138
var outputs []FrontendTLSConfig
141139
basePath := c.FrontendTLSJobBasePath()
142140
for i, cert := range c.FrontendTLSJob {
@@ -165,9 +163,7 @@ func (c *Config) initConfigFromFile(path string) error {
165163

166164
dirPath := filepath.Join(basePath, name)
167165
if err := os.MkdirAll(dirPath, 0750); err != nil {
168-
if !(isReadOnlyFS(err) || isPermissionDenied(err)) {
169-
return err
170-
}
166+
return err
171167
}
172168

173169
certFilePath := filepath.Join(dirPath, fmt.Sprintf("%s.pem", name))
@@ -280,36 +276,14 @@ func certHasSAN(cert *x509.Certificate) bool {
280276
return hasSANExtension || hasDNSEntries
281277
}
282278

283-
// writeFile writes data to the given path with the specified file mode and ownership.
284-
//
285-
// this function is accessed from:
286-
// 1. prestart errand which has the necessary privs and is responsible for creating the files
287-
// 2. tcp_router_ctl which doesn't have the necessary privs but also invokes this function
288-
// and so can be safely skipped
289279
func writeFile(path string, data []byte, mode os.FileMode, uid, gid int) error {
290280
if err := os.WriteFile(path, data, mode); err != nil {
291-
if isReadOnlyFS(err) || isPermissionDenied(err) {
292-
return nil
293-
}
294281
return err
295282
}
296283

297284
if err := os.Chown(path, uid, gid); err != nil {
298-
if isReadOnlyFS(err) || isPermissionDenied(err) {
299-
return nil
300-
}
301285
return err
302286
}
303287

304288
return nil
305289
}
306-
307-
func isReadOnlyFS(err error) bool {
308-
return errors.Is(err, syscall.EROFS)
309-
}
310-
311-
func isPermissionDenied(err error) bool {
312-
return errors.Is(err, syscall.EPERM) ||
313-
errors.Is(err, syscall.EACCES) ||
314-
errors.Is(err, os.ErrPermission)
315-
}

src/code.cloudfoundry.org/cf-tcp-router/config/config_test.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ var _ = Describe("Config", Serial, func() {
9393
ClientCertAndKeyPath: certAndKeyFile,
9494
},
9595
}
96-
cfg, err := config.New("fixtures/valid_config.yml")
96+
cfg, err := config.New("fixtures/valid_config.yml", false)
9797
Expect(err).NotTo(HaveOccurred())
9898
Expect(*cfg).To(Equal(expectedCfg))
9999
})
@@ -102,13 +102,13 @@ var _ = Describe("Config", Serial, func() {
102102
Context("when given an invalid config", func() {
103103
Context("non existing config", func() {
104104
It("return error", func() {
105-
_, err := config.New("fixtures/non_existing_config.yml")
105+
_, err := config.New("fixtures/non_existing_config.yml", false)
106106
Expect(err).To(HaveOccurred())
107107
})
108108
})
109109
Context("malformed YAML config", func() {
110110
It("return error", func() {
111-
_, err := config.New("fixtures/malformed_config.yml")
111+
_, err := config.New("fixtures/malformed_config.yml", false)
112112
Expect(err).To(HaveOccurred())
113113
})
114114
})
@@ -118,23 +118,23 @@ var _ = Describe("Config", Serial, func() {
118118
Context("is enabled", func() {
119119
Context("when the CA path is not a valid CA", func() {
120120
It("returns an error", func() {
121-
_, err := config.New("fixtures/bad_ca_config.yml")
121+
_, err := config.New("fixtures/bad_ca_config.yml", false)
122122
Expect(err).To(HaveOccurred())
123123
Expect(err.Error()).To(ContainSubstring("Invalid PEM block found in file"))
124124
})
125125
})
126126

127127
Context("when the Client Cert/key pair are not valid", func() {
128128
It("returns an error", func() {
129-
_, err := config.New("fixtures/bad_client_cert_config.yml")
129+
_, err := config.New("fixtures/bad_client_cert_config.yml", false)
130130
Expect(err).To(HaveOccurred())
131131
Expect(err.Error()).To(ContainSubstring("Invalid PEM CERTIFICATE found in file"))
132132
})
133133
})
134134

135135
Context("when the Client Cert/key pair are mismatched", func() {
136136
It("returns an error", func() {
137-
_, err := config.New("fixtures/mismatched_client_cert_config.yml")
137+
_, err := config.New("fixtures/mismatched_client_cert_config.yml", false)
138138
Expect(err).To(HaveOccurred())
139139
Expect(err.Error()).To(ContainSubstring("Unable to validate backend TLS client cert + key in file"))
140140
Expect(err.Error()).To(ContainSubstring("tls: private key does not match public key"))
@@ -143,7 +143,7 @@ var _ = Describe("Config", Serial, func() {
143143

144144
Context("when CA path is not specified", func() {
145145
It("returns an error", func() {
146-
_, err := config.New("fixtures/no_ca.yml")
146+
_, err := config.New("fixtures/no_ca.yml", false)
147147
Expect(err).To(HaveOccurred())
148148
Expect(err.Error()).To(ContainSubstring("Backend TLS was enabled but no CA certificates were specified"))
149149
})
@@ -152,7 +152,7 @@ var _ = Describe("Config", Serial, func() {
152152

153153
Context("is disabled", func() {
154154
It("does not set any of the backend_tls cert/ca values", func() {
155-
cfg, err := config.New("fixtures/disabled_tls.yml")
155+
cfg, err := config.New("fixtures/disabled_tls.yml", false)
156156
Expect(err).NotTo(HaveOccurred())
157157
Expect(cfg.BackendTLS).To(Equal(config.BackendTLSConfig{
158158
Enabled: false,
@@ -163,7 +163,7 @@ var _ = Describe("Config", Serial, func() {
163163

164164
Context("when haproxy pid file is missing", func() {
165165
It("return error", func() {
166-
_, err := config.New("fixtures/no_haproxy.yml")
166+
_, err := config.New("fixtures/no_haproxy.yml", false)
167167
Expect(err).To(HaveOccurred())
168168
})
169169
})
@@ -177,7 +177,7 @@ var _ = Describe("Config", Serial, func() {
177177
},
178178
HaProxyPidFile: "/path/to/pid/file",
179179
}
180-
cfg, err := config.New("fixtures/no_oauth.yml")
180+
cfg, err := config.New("fixtures/no_oauth.yml", false)
181181
Expect(err).NotTo(HaveOccurred())
182182
Expect(*cfg).To(Equal(expectedCfg))
183183
})
@@ -199,15 +199,15 @@ var _ = Describe("Config", Serial, func() {
199199
},
200200
HaProxyPidFile: "/path/to/pid/file",
201201
}
202-
cfg, err := config.New("fixtures/missing_oauth_fields.yml")
202+
cfg, err := config.New("fixtures/missing_oauth_fields.yml", false)
203203
Expect(err).NotTo(HaveOccurred())
204204
Expect(*cfg).To(Equal(expectedCfg))
205205
})
206206
})
207207

208208
Context("when drain_wait is a negative number", func() {
209209
It("defaults to 20s", func() {
210-
cfg, err := config.New("fixtures/negative_drain_wait.yml")
210+
cfg, err := config.New("fixtures/negative_drain_wait.yml", false)
211211
Expect(err).NotTo(HaveOccurred())
212212
Expect(cfg.DrainWaitDuration).To(Equal(20 * time.Second))
213213
})
@@ -231,7 +231,7 @@ var _ = Describe("Config", Serial, func() {
231231

232232
Context("with valid cert and key", func() {
233233
BeforeEach(func() {
234-
cfg, err = config.New("fixtures/valid_frontend_cert.yml")
234+
cfg, err = config.New("fixtures/valid_frontend_cert.yml", true)
235235
})
236236

237237
It("loads config without error", func() {
@@ -274,7 +274,7 @@ var _ = Describe("Config", Serial, func() {
274274

275275
Context("with invalid cert and key", func() {
276276
BeforeEach(func() {
277-
cfg, err = config.New("fixtures/valid_frontend_cert.yml")
277+
cfg, err = config.New("fixtures/valid_frontend_cert.yml", true)
278278
})
279279

280280
It("loads config without error", func() {
@@ -325,17 +325,17 @@ var _ = Describe("Config", Serial, func() {
325325

326326
Context("with invalid frontend_tls config", func() {
327327
It("should fail if cert_chain is missing SAN information", func() {
328-
_, err := config.New("fixtures/frontend_cert_without_san.yml")
328+
_, err := config.New("fixtures/frontend_cert_without_san.yml", true)
329329
Expect(err).To(HaveOccurred())
330330
Expect(err.Error()).To(Equal("frontend_tls[0].cert_chain must include a subjectAltName extension"))
331331
})
332332
It("should fail if certs or keys are empty", func() {
333-
_, err := config.New("fixtures/no_frontend_certs.yml")
333+
_, err := config.New("fixtures/no_frontend_certs.yml", true)
334334
Expect(err).To(HaveOccurred())
335335
Expect(err.Error()).To(Equal("frontend_tls[0] must include name, cert_chain, and private_key"))
336336
})
337337
It("should fail if cert is invalid", func() {
338-
_, err := config.New("fixtures/invalid_frontend_certs.yml")
338+
_, err := config.New("fixtures/invalid_frontend_certs.yml", true)
339339
Expect(err).To(HaveOccurred())
340340
Expect(err.Error()).To(Equal("failed to parse PEM block"))
341341
})

0 commit comments

Comments
 (0)