Skip to content

Commit c2e4c45

Browse files
authored
feat(kiali): standardize Certificate Authority Configuration Method (review) (#528)
Signed-off-by: Marc Nuri <marc@marcnuri.com>
1 parent a86eccd commit c2e4c45

File tree

3 files changed

+6
-106
lines changed

3 files changed

+6
-106
lines changed

AGENTS.md

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -48,92 +48,6 @@ When adding a new tool:
4848
3. Add the tool to an appropriate toolset (or create a new toolset if needed).
4949
4. Register the toolset in `pkg/toolsets/` if it's a new toolset.
5050

51-
### Configuration Standards for Red Hat-Maintained Components
52-
53-
To ensure consistency across Red Hat-maintained toolsets and cluster providers, follow these standards when implementing certificate authority (CA) configuration:
54-
55-
#### Certificate Authority (CA) Configuration Standard
56-
57-
**Standard Pattern:** Certificate authorities must be configured using **file paths**, not inline PEM content.
58-
59-
**Implementation Guidelines:**
60-
61-
1. **Config Parser (`pkg/toolsets/<toolset>/config.go`):**
62-
- Accept `certificate_authority` as a string field in your toolset config struct.
63-
- In the toolset parser function, resolve relative paths using `config.ConfigDirPathFromContext(ctx)` to make them relative to the config file directory.
64-
- Store the resolved absolute path in the config struct.
65-
- Validate in the `Validate()` method that `certificate_authority` is a valid file path using `os.Stat()`.
66-
67-
Example:
68-
```go
69-
func (c *Config) Validate() error {
70-
// ... other validations ...
71-
72-
// Validate that certificate_authority is a valid file
73-
if caValue := strings.TrimSpace(c.CertificateAuthority); caValue != "" {
74-
if _, err := os.Stat(caValue); err != nil {
75-
return fmt.Errorf("certificate_authority must be a valid file path: %w", err)
76-
}
77-
}
78-
return nil
79-
}
80-
81-
func toolsetParser(ctx context.Context, primitive toml.Primitive, md toml.MetaData) (config.Extended, error) {
82-
var cfg Config
83-
if err := md.PrimitiveDecode(primitive, &cfg); err != nil {
84-
return nil, err
85-
}
86-
87-
// Resolve relative CA file paths
88-
if cfg.CertificateAuthority != "" {
89-
configDir := config.ConfigDirPathFromContext(ctx)
90-
if configDir != "" && !filepath.IsAbs(cfg.CertificateAuthority) {
91-
cfg.CertificateAuthority = filepath.Join(configDir, cfg.CertificateAuthority)
92-
}
93-
}
94-
95-
return &cfg, nil
96-
}
97-
```
98-
99-
2. **Client Implementation:**
100-
- When using the CA certificate, read it from the file path using `os.ReadFile()`.
101-
- Only valid file paths are supported; the path must exist and be readable.
102-
103-
Example:
104-
```go
105-
func (c *Client) createHTTPClient() *http.Client {
106-
tlsConfig := &tls.Config{InsecureSkipVerify: c.insecure}
107-
108-
if caValue := strings.TrimSpace(c.certificateAuthority); caValue != "" {
109-
// Read the certificate from file
110-
caPEM, err := os.ReadFile(caValue)
111-
if err != nil {
112-
// Handle error appropriately
113-
}
114-
115-
// Use caPEM to configure TLS...
116-
}
117-
118-
return &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
119-
}
120-
```
121-
122-
3. **Documentation:**
123-
- Document that `certificate_authority` accepts only a file path (absolute or relative).
124-
- Mention that relative paths are resolved relative to the config file directory.
125-
- Note that the file path must exist and be readable; invalid paths will cause validation to fail.
126-
127-
**Reference Implementation:**
128-
- See `pkg/kiali/config.go` and `pkg/kiali/kiali.go` for a complete example.
129-
- See `pkg/kubernetes-mcp-server/cmd/root.go` (lines 292-314) for how the main server handles CA files.
130-
131-
**Rationale:**
132-
- Consistency with ACM cluster provider and other Red Hat-maintained components.
133-
- Better security practices (certificates stored in files, not in config files).
134-
- Easier management and rotation of certificates.
135-
- Clearer separation of configuration and secrets.
136-
13751
## Building
13852

13953
Use the provided Makefile targets:

pkg/config/config.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,13 @@ type GroupVersionKind struct {
8989

9090
type ReadConfigOpt func(cfg *StaticConfig)
9191

92-
func withDirPath(path string) ReadConfigOpt {
92+
// WithDirPath returns a ReadConfigOpt that sets the config directory path.
93+
func WithDirPath(path string) ReadConfigOpt {
9394
return func(cfg *StaticConfig) {
9495
cfg.configDirPath = path
9596
}
9697
}
9798

98-
// WithDirPath returns a ReadConfigOpt that sets the config directory path.
99-
func WithDirPath(path string) ReadConfigOpt {
100-
return withDirPath(path)
101-
}
102-
10399
// Read reads the toml file and returns the StaticConfig, with any opts applied.
104100
func Read(configPath string, opts ...ReadConfigOpt) (*StaticConfig, error) {
105101
configData, err := os.ReadFile(configPath)
@@ -114,7 +110,7 @@ func Read(configPath string, opts ...ReadConfigOpt) (*StaticConfig, error) {
114110
}
115111
dirPath := filepath.Dir(absPath)
116112

117-
cfg, err := ReadToml(configData, append(opts, withDirPath(dirPath))...)
113+
cfg, err := ReadToml(configData, append(opts, WithDirPath(dirPath))...)
118114
if err != nil {
119115
return nil, err
120116
}

pkg/kiali/config_test.go

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,14 @@ type ConfigSuite struct {
1717
}
1818

1919
func (s *ConfigSuite) SetupTest() {
20-
// Create a temporary directory for test files
21-
tempDir, err := os.MkdirTemp("", "kiali-config-test-*")
22-
s.Require().NoError(err, "Failed to create temp directory")
23-
s.tempDir = tempDir
24-
2520
// Create a test CA certificate file
21+
s.tempDir = s.T().TempDir()
2622
s.caFile = filepath.Join(s.tempDir, "ca.crt")
27-
err = os.WriteFile(s.caFile, []byte("test ca content"), 0644)
23+
err := os.WriteFile(s.caFile, []byte("test ca content"), 0644)
2824
s.Require().NoError(err, "Failed to write CA file")
2925
}
3026

3127
func (s *ConfigSuite) TestConfigParser_ResolvesRelativePath() {
32-
// Create CA file in temp directory
33-
caFile := filepath.Join(s.tempDir, "ca.crt")
34-
err := os.WriteFile(caFile, []byte("test ca content"), 0644)
35-
s.Require().NoError(err, "Failed to write CA file")
36-
3728
// Read config with configDirPath set to tempDir to resolve relative paths
3829
cfg := test.Must(config.ReadToml([]byte(`
3930
[toolset_configs.kiali]
@@ -48,8 +39,7 @@ func (s *ConfigSuite) TestConfigParser_ResolvesRelativePath() {
4839
s.Require().True(ok, "Kiali config should be of type *Config")
4940

5041
// Verify the path was resolved to absolute
51-
expectedPath := caFile
52-
s.Equal(expectedPath, kcfg.CertificateAuthority, "Relative path should be resolved to absolute path")
42+
s.Equal(s.caFile, kcfg.CertificateAuthority, "Relative path should be resolved to absolute path")
5343
}
5444

5545
func (s *ConfigSuite) TestConfigParser_PreservesAbsolutePath() {

0 commit comments

Comments
 (0)