Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions internal/installer/config_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,39 @@ func (g *InstallConfig) ValidateInstallConfig() []string {
}
}

errors = append(errors, validateOpenFga(g.Config.Codesphere.OpenFga)...)

return errors
}

// validateOpenFga checks the codesphere.openFga block. A data center that does not deploy
// OpenFGA has nowhere to fall back to, so it must name the instance it uses; a data center that
// exposes one must say under which host.
func validateOpenFga(config *files.OpenFgaConfig) []string {
if config == nil {
return nil
}

errors := []string{}
if !config.DeploysOpenFga() && config.APIURL == "" {
errors = append(errors, "OpenFGA apiUrl is required when codesphere.openFga.deploy is false")
}

if config.APIURL != "" {
if _, err := url.ParseRequestURI(config.APIURL); err != nil {
errors = append(errors, "OpenFGA apiUrl must be a valid URL")
}
}

if config.ExposesOpenFga() {
if config.Expose.Host == "" {
errors = append(errors, "OpenFGA expose host is required when codesphere.openFga.expose.enabled is true")
}

if !config.DeploysOpenFga() {
errors = append(errors, "OpenFGA cannot be exposed by a data center that does not deploy it")
}
}
return errors
}

Expand Down
49 changes: 49 additions & 0 deletions internal/installer/config_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,55 @@ var _ = Describe("ConfigManager", func() {
})
})

Context("openFga validation", func() {
It("should accept an absent openFga block", func() {
configManager.Config.Codesphere.OpenFga = nil
errors := configManager.ValidateInstallConfig()
Expect(errors).NotTo(ContainElement(ContainSubstring("OpenFGA")))
})

It("should require an apiUrl when the data center does not deploy OpenFGA", func() {
deploy := false
configManager.Config.Codesphere.OpenFga = &files.OpenFgaConfig{Deploy: &deploy}
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("OpenFGA apiUrl is required")))
})

It("should validate the apiUrl format", func() {
configManager.Config.Codesphere.OpenFga = &files.OpenFgaConfig{APIURL: "not-a-valid-url"}
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("OpenFGA apiUrl must be a valid URL")))
})

It("should require a host when exposing OpenFGA", func() {
configManager.Config.Codesphere.OpenFga = &files.OpenFgaConfig{
Expose: &files.OpenFgaExposeConfig{Enabled: true},
}
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("OpenFGA expose host is required")))
})

It("should reject exposing an OpenFGA the data center does not deploy", func() {
deploy := false
configManager.Config.Codesphere.OpenFga = &files.OpenFgaConfig{
Deploy: &deploy,
APIURL: "https://openfga.1.cs.example.com",
Expose: &files.OpenFgaExposeConfig{Enabled: true, Host: "openfga.2.cs.example.com"},
}
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("cannot be exposed by a data center that does not deploy it")))
})

It("should accept a data center that deploys and exposes OpenFGA", func() {
configManager.Config.Codesphere.OpenFga = &files.OpenFgaConfig{
APIURL: "https://openfga.1.cs.example.com",
Expose: &files.OpenFgaExposeConfig{Enabled: true, Host: "openfga.1.cs.example.com"},
}
errors := configManager.ValidateInstallConfig()
Expect(errors).NotTo(ContainElement(ContainSubstring("OpenFGA")))
})
})

Context("ceph validation", func() {
It("should require at least one Ceph host", func() {
configManager.Config.Ceph.Hosts = []files.CephHost{}
Expand Down
34 changes: 34 additions & 0 deletions internal/installer/files/config_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ type CodesphereConfig struct {
ManagedServices []ManagedServiceConfig `yaml:"managedServices,omitempty"`
OpenBao *OpenBaoConfig `yaml:"openBao,omitempty"`
OpenfgaBackups *OpenfgaBackupsConfig `yaml:"openfgaBackups,omitempty"`
OpenFga *OpenFgaConfig `yaml:"openFga,omitempty"`
Migration *MigrationConfig `yaml:"migration,omitempty"`
TelemetryExport *TelemetryExport `yaml:"telemetryExport,omitempty"`
Override ChartOverride `yaml:"override,omitempty"`
Expand Down Expand Up @@ -398,6 +399,39 @@ type OpenfgaBackupsConfig struct {
RetentionPolicy string `yaml:"retentionPolicy,omitempty"`
}

// OpenFgaConfig configures the authorization store. One OpenFGA instance serves a whole
// installation, so in a multi-data-center setup exactly one data center deploys and exposes
// it (Deploy + Expose) and every other one only points at it (APIURL).
type OpenFgaConfig struct {
// Deploy controls whether pc-applications deploys OpenFGA in this data center.
// Defaults to true when unset, matching the pc-applications chart.
Deploy *bool `yaml:"deploy,omitempty"`
// APIURL is the URL the Codesphere services reach OpenFGA at. Defaults to the
// in-cluster service of a locally deployed OpenFGA; required when Deploy is false.
APIURL string `yaml:"apiUrl,omitempty"`
// Expose publishes the deployed OpenFGA through the Codesphere gateway so the other
// data centers can reach it.
Expose *OpenFgaExposeConfig `yaml:"expose,omitempty"`
}

// OpenFgaExposeConfig publishes a locally deployed OpenFGA through the Codesphere gateway.
type OpenFgaExposeConfig struct {
Enabled bool `yaml:"enabled"`
Comment thread
NautiluX marked this conversation as resolved.
// Host OpenFGA is served under. Must resolve to this data center's public IP and
// is what the other data centers put in their APIURL.
Host string `yaml:"host,omitempty"`
}

// DeploysOpenFga reports whether pc-applications should deploy OpenFGA in this data center.
func (c *OpenFgaConfig) DeploysOpenFga() bool {
return c == nil || c.Deploy == nil || *c.Deploy
}

// ExposesOpenFga reports whether the deployed OpenFGA is published through the gateway.
func (c *OpenFgaConfig) ExposesOpenFga() bool {
return c != nil && c.Expose != nil && c.Expose.Enabled
}

type OAuthProvidersConfig struct {
Oidc *OidcOAuthProvider `yaml:"oidc,omitempty"`
}
Expand Down
Loading