30939 Migrating CAs from App Config JSON to their own table (#31739)
Migrates CAs out of the App Config JSON and into their own table including their secrets. Does not implement CRUD endpoints or update clients of existing app config to use them yet. I think there are good arguments both for keeping secrets in separate tables and keeping them in this table but on balance I felt it was best to move everything CA to this new table # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [x] Added/updated automated tests - [x] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually ## Database migrations - [x] Checked table schema to confirm autoupdate - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects. - [x] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`).
This commit is contained in:
+236
@@ -0,0 +1,236 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/jmoiron/sqlx/reflectx"
|
||||
)
|
||||
|
||||
func init() {
|
||||
MigrationClient.AddMigration(Up_20250811084533, Down_20250811084533)
|
||||
}
|
||||
|
||||
// dbCertificateAuthority embeds fleet.CertificateAuthority and adds encrypted representation of sensitive
|
||||
// fields for handling DB operations
|
||||
type dbCertificateAuthority struct {
|
||||
fleet.CertificateAuthority
|
||||
// Digicert
|
||||
APITokenEncrypted []byte `db:"api_token_encrypted"`
|
||||
CertificateUserPrincipalNamesRaw []byte `db:"certificate_user_principal_names"`
|
||||
|
||||
// NDES SCEP Proxy
|
||||
PasswordEncrypted []byte `db:"password_encrypted"`
|
||||
|
||||
// Custom SCEP Proxy
|
||||
ChallengeEncrypted []byte `db:"challenge_encrypted"`
|
||||
|
||||
// Hydrant
|
||||
ClientSecretEncrypted []byte `db:"client_secret_encrypted"`
|
||||
}
|
||||
|
||||
func Up_20250811084533(tx *sql.Tx) error {
|
||||
txx := sqlx.Tx{Tx: tx, Mapper: reflectx.NewMapperFunc("db", sqlx.NameMapper)}
|
||||
stmt := `
|
||||
CREATE TABLE IF NOT EXISTS certificate_authorities (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
type ENUM('digicert', 'ndes_scep_proxy', 'custom_scep_proxy', 'hydrant') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
|
||||
-- Common fields
|
||||
name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, -- Used by digicert and custom_scep_proxy
|
||||
url TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, -- Used by all types
|
||||
|
||||
-- DigiCert fields
|
||||
api_token_encrypted BLOB, -- previously stored in ca_config_assets
|
||||
profile_id VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
certificate_common_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
certificate_user_principal_names JSON, -- Array of UPNs
|
||||
certificate_seat_id VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
|
||||
-- NDES fields
|
||||
admin_url TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
username VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
password_encrypted BLOB, -- previously stored in mdm_config_assets
|
||||
|
||||
-- Custom SCEP
|
||||
challenge_encrypted BLOB, -- previously stored in ca_config_assets
|
||||
|
||||
-- Hydrant fields
|
||||
client_id VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
client_secret_encrypted BLOB,
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
`
|
||||
|
||||
// Create the table then iterate through app_config_json to populate it
|
||||
_, err := txx.Exec(stmt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create certificate_authorities table: %w", err)
|
||||
}
|
||||
|
||||
// Create unique indexes on name and type(i.e. can't have more than 1 CA of a given type with a
|
||||
// given name)
|
||||
_, err = txx.Exec(`CREATE UNIQUE INDEX idx_ca_type_name ON certificate_authorities (type, name)`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create unique index on certificate_authorities: %w", err)
|
||||
}
|
||||
|
||||
// Populate the table with existing data from app_config_json
|
||||
// if appConfigJSON.integrations.ndes_scep_proxy ...
|
||||
// if appConfigJSON.integrations.custom_scep_proxy
|
||||
// if appConfigJSON.integrations.hydrant ...
|
||||
// if appConfigJSON.integrations.digicert ...
|
||||
|
||||
appConfigSelect := `SELECT json_value FROM app_config_json LIMIT 1`
|
||||
var appConfigJSON fleet.AppConfig
|
||||
jsonBytes := []byte{}
|
||||
if err := txx.Get(&jsonBytes, appConfigSelect); err != nil {
|
||||
return fmt.Errorf("failed to get app_config_json: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(jsonBytes, &appConfigJSON); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal app_config_json: %w", err)
|
||||
}
|
||||
|
||||
configAssets := []fleet.CAConfigAsset{}
|
||||
assetSelectStmt := `
|
||||
SELECT
|
||||
name, type, value
|
||||
FROM
|
||||
ca_config_assets
|
||||
`
|
||||
if err := txx.Select(&configAssets, assetSelectStmt); err != nil {
|
||||
return fmt.Errorf("failed to get ca_config_assets: %w", err)
|
||||
}
|
||||
|
||||
getCAConfigAsset := func(name string, assetType fleet.CAConfigAssetType) *fleet.CAConfigAsset {
|
||||
for _, asset := range configAssets {
|
||||
if asset.Name == name && asset.Type == assetType {
|
||||
return &asset
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
casToInsert := []dbCertificateAuthority{}
|
||||
|
||||
if appConfigJSON.Integrations.CustomSCEPProxy.Valid && len(appConfigJSON.Integrations.CustomSCEPProxy.Value) > 0 {
|
||||
for _, customSCEPProxyCA := range appConfigJSON.Integrations.CustomSCEPProxy.Value {
|
||||
customSCEPChallenge := getCAConfigAsset(customSCEPProxyCA.Name, fleet.CAConfigCustomSCEPProxy)
|
||||
if customSCEPChallenge == nil || len(customSCEPChallenge.Value) == 0 {
|
||||
return errors.New("Custom SCEP Proxy challenge not found in ca_config_assets")
|
||||
}
|
||||
casToInsert = append(casToInsert, dbCertificateAuthority{
|
||||
CertificateAuthority: fleet.CertificateAuthority{
|
||||
Type: string(fleet.CATypeCustomSCEPProxy),
|
||||
Name: customSCEPProxyCA.Name,
|
||||
URL: customSCEPProxyCA.URL,
|
||||
},
|
||||
ChallengeEncrypted: customSCEPChallenge.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
if appConfigJSON.Integrations.DigiCert.Valid && len(appConfigJSON.Integrations.DigiCert.Value) > 0 {
|
||||
for _, digicertCA := range appConfigJSON.Integrations.DigiCert.Value {
|
||||
digicertAPIToken := getCAConfigAsset(digicertCA.Name, fleet.CAConfigDigiCert)
|
||||
if digicertAPIToken == nil || len(digicertAPIToken.Value) == 0 {
|
||||
return errors.New("DigiCert API token not found in ca_config_assets")
|
||||
}
|
||||
casToInsert = append(casToInsert, dbCertificateAuthority{
|
||||
CertificateAuthority: fleet.CertificateAuthority{
|
||||
Type: string(fleet.CATypeDigiCert),
|
||||
Name: digicertCA.Name,
|
||||
URL: digicertCA.URL,
|
||||
ProfileID: &digicertCA.ProfileID,
|
||||
CertificateCommonName: &digicertCA.CertificateCommonName,
|
||||
CertificateUserPrincipalNames: digicertCA.CertificateUserPrincipalNames,
|
||||
CertificateSeatID: &digicertCA.CertificateSeatID,
|
||||
},
|
||||
APITokenEncrypted: digicertAPIToken.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if appConfigJSON.Integrations.NDESSCEPProxy.Valid {
|
||||
ndesCAPassword := []byte{}
|
||||
err = txx.Get(&ndesCAPassword, `SELECT value FROM mdm_config_assets WHERE name = ?`, fleet.MDMAssetNDESPassword)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get NDES SCEP Proxy password: %w", err)
|
||||
}
|
||||
if len(ndesCAPassword) == 0 {
|
||||
return errors.New("NDES SCEP Proxy password not found in mdm_config_assets")
|
||||
}
|
||||
|
||||
// Insert NDES SCEP Proxy data
|
||||
ndesCA := appConfigJSON.Integrations.NDESSCEPProxy.Value
|
||||
dbNDESCA := dbCertificateAuthority{
|
||||
CertificateAuthority: fleet.CertificateAuthority{
|
||||
Type: string(fleet.CATypeNDESSCEPProxy),
|
||||
Name: "DEFAULT_NDES_CA",
|
||||
URL: ndesCA.URL,
|
||||
AdminURL: &ndesCA.AdminURL,
|
||||
Username: &ndesCA.Username,
|
||||
},
|
||||
PasswordEncrypted: ndesCAPassword,
|
||||
}
|
||||
casToInsert = append(casToInsert, dbNDESCA)
|
||||
}
|
||||
|
||||
for _, ca := range casToInsert {
|
||||
insertStmt := `
|
||||
INSERT INTO certificate_authorities (
|
||||
type,
|
||||
name,
|
||||
url,
|
||||
api_token_encrypted,
|
||||
profile_id,
|
||||
certificate_common_name,
|
||||
certificate_user_principal_names,
|
||||
certificate_seat_id,
|
||||
admin_url,
|
||||
username,
|
||||
password_encrypted,
|
||||
challenge_encrypted,
|
||||
client_id,
|
||||
client_secret_encrypted
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
var upns []byte
|
||||
if ca.CertificateUserPrincipalNames != nil {
|
||||
upns, err = json.Marshal(ca.CertificateUserPrincipalNames)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal certificate user principal names for %s: %w", ca.Name, err)
|
||||
}
|
||||
}
|
||||
args := []interface{}{
|
||||
ca.Type,
|
||||
ca.Name,
|
||||
ca.URL,
|
||||
ca.APITokenEncrypted,
|
||||
ca.ProfileID,
|
||||
ca.CertificateCommonName,
|
||||
upns,
|
||||
ca.CertificateSeatID,
|
||||
ca.AdminURL,
|
||||
ca.Username,
|
||||
ca.PasswordEncrypted,
|
||||
ca.ChallengeEncrypted,
|
||||
ca.ClientID,
|
||||
ca.ClientSecretEncrypted,
|
||||
}
|
||||
_, err = txx.Exec(insertStmt, args...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert certificate authority %s: %w", ca.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Down_20250811084533(tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"crypto/md5" // nolint:gosec // used only to hash for efficient comparisons
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func md5ChecksumBytes(b []byte) string {
|
||||
rawChecksum := md5.Sum(b) //nolint:gosec
|
||||
return strings.ToUpper(hex.EncodeToString(rawChecksum[:]))
|
||||
}
|
||||
|
||||
func TestUp_20250811084533(t *testing.T) {
|
||||
db := applyUpToPrev(t)
|
||||
var appConfigJSON fleet.AppConfig
|
||||
const (
|
||||
digicertCA1Name = "DigiCert_CA_1"
|
||||
digicertCA2Name = "DigiCert_CA_2"
|
||||
customSCEPCA1Name = "Custom_SCEP_Proxy_CA_1"
|
||||
customSCEPCA2Name = "Custom_SCEP_Proxy_CA_2"
|
||||
)
|
||||
// various strings encrypted with key my-secret-key-123456781234567890 just to verify the
|
||||
// migration works with opaque(to it) binary data
|
||||
customSCEPCA1EncryptedChallenge := []byte{0xe0, 0xd1, 0xba, 0x48, 0x20, 0x31, 0xff, 0x52, 0x11, 0x2c, 0x62, 0x0d, 0x8e, 0xc3, 0xb7, 0x88, 0x13, 0x5d, 0x37, 0x04, 0x10, 0xf4, 0xda, 0xa4, 0x8e, 0x18, 0xf7, 0x95, 0x8f, 0x5d, 0x1c, 0xc4, 0xb7, 0x45, 0xeb, 0xa9, 0xbf, 0x7d}
|
||||
customSCEPCA2EncryptedChallenge := []byte{0x8b, 0x92, 0x95, 0xbf, 0xda, 0xc1, 0x71, 0x11, 0x64, 0xdc, 0xd0, 0xa8, 0x1c, 0x91, 0x26, 0xec, 0x15, 0xd5, 0x21, 0xca, 0x5e, 0x62, 0x71, 0x01, 0x5e, 0xb1, 0xb1, 0xbf, 0x9f, 0xe6, 0x36, 0x79, 0xa2, 0xee, 0x32, 0x9d, 0x64, 0x7c}
|
||||
ndesEncryptedPassword := []byte{0xaa, 0x20, 0x6e, 0xb0, 0xb5, 0x10, 0x52, 0x6d, 0xe2, 0x78, 0x14, 0xbe, 0xc5, 0xe0, 0x8a, 0x04, 0xa6, 0xfd, 0x8b, 0x17, 0xd8, 0x15, 0x71, 0x3c, 0x72, 0xa2, 0x76, 0x5f, 0xba, 0x5d, 0x10, 0x41, 0x21, 0x56, 0xe4, 0x1d, 0xa0, 0x90, 0x0d, 0x9e, 0xe1}
|
||||
digicertCA1EncryptedPassword := []byte{0xd5, 0xf1, 0x50, 0x6f, 0x59, 0xb4, 0xfe, 0xa4, 0x3a, 0xc4, 0x24, 0xc8, 0xfa, 0xfd, 0x43, 0xc0, 0xec, 0x2d, 0x10, 0xb1, 0x2a, 0x1e, 0xa8, 0x1e, 0x62, 0x2f, 0x04, 0xeb, 0xb5, 0x55, 0xea, 0x92, 0xfe, 0xb2, 0x9b, 0x6b, 0xc0, 0x98, 0x70, 0x2c, 0x33, 0xf6, 0x01, 0x0f, 0x13, 0x06, 0xef, 0xee, 0x81, 0xb9}
|
||||
digicertCA2EncryptedPassword := []byte{0x24, 0x46, 0x38, 0xa5, 0x75, 0xe4, 0x34, 0x2a, 0x99, 0x5d, 0x52, 0xc9, 0xb1, 0x05, 0x05, 0xa1, 0xdf, 0x62, 0xe2, 0xf1, 0x01, 0x92, 0x0b, 0xcd, 0xd4, 0x49, 0x83, 0x2e, 0xff, 0xd6, 0x23, 0x5c, 0x75, 0x57, 0x57, 0x18, 0x42, 0x3c, 0x81, 0x78, 0xf2, 0x86, 0x59, 0x42, 0x11, 0xb5, 0x82, 0x23, 0x3a, 0x91}
|
||||
ndesCA := fleet.NDESSCEPProxyIntegration{
|
||||
URL: "https://ndes.example.com",
|
||||
AdminURL: "https://admin.ndes.example.com",
|
||||
Username: "admin",
|
||||
Password: fleet.MaskedPassword,
|
||||
}
|
||||
|
||||
digicertCAs := []fleet.DigiCertIntegration{{
|
||||
URL: "https://api.digicert.com",
|
||||
ProfileID: "profile-id-1",
|
||||
Name: digicertCA1Name,
|
||||
APIToken: fleet.MaskedPassword,
|
||||
CertificateCommonName: "Common-Name1: $FLEET_VAR_HOST_HARDWARE_SERIAL",
|
||||
CertificateUserPrincipalNames: []string{"UPN1: $FLEET_VAR_HOST_HARDWARE_SERIAL"},
|
||||
CertificateSeatID: "Seat-ID1: $FLEET_VAR_HOST_HARDWARE_SERIAL",
|
||||
}, {
|
||||
URL: "https://api.digicert.com",
|
||||
ProfileID: "profile-id-2",
|
||||
Name: digicertCA2Name,
|
||||
APIToken: fleet.MaskedPassword,
|
||||
CertificateCommonName: "Common-Name2: $FLEET_VAR_HOST_HARDWARE_SERIAL",
|
||||
CertificateUserPrincipalNames: []string{"UPN2: $FLEET_VAR_HOST_HARDWARE_SERIAL"},
|
||||
CertificateSeatID: "Seat-ID2: $FLEET_VAR_HOST_HARDWARE_SERIAL",
|
||||
}}
|
||||
customSCEPProxyCAs := []fleet.CustomSCEPProxyIntegration{{
|
||||
URL: "https://custom-scep-1.example.com",
|
||||
Name: customSCEPCA1Name,
|
||||
Challenge: fleet.MaskedPassword,
|
||||
}, {
|
||||
URL: "https://custom-scep-2.example.com",
|
||||
Name: customSCEPCA2Name,
|
||||
Challenge: fleet.MaskedPassword,
|
||||
}}
|
||||
appConfigJSON.Integrations.CustomSCEPProxy.Value = customSCEPProxyCAs
|
||||
appConfigJSON.Integrations.CustomSCEPProxy.Set = true
|
||||
appConfigJSON.Integrations.CustomSCEPProxy.Valid = true
|
||||
appConfigJSON.Integrations.NDESSCEPProxy.Value = ndesCA
|
||||
appConfigJSON.Integrations.NDESSCEPProxy.Set = true
|
||||
appConfigJSON.Integrations.NDESSCEPProxy.Valid = true
|
||||
appConfigJSON.Integrations.DigiCert.Value = digicertCAs
|
||||
appConfigJSON.Integrations.DigiCert.Set = true
|
||||
appConfigJSON.Integrations.DigiCert.Valid = true
|
||||
|
||||
jsonBytes, err := json.Marshal(&appConfigJSON)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal appConfigJSON: %v", err)
|
||||
}
|
||||
|
||||
insertNDESPasswordStmt := `INSERT INTO mdm_config_assets (name, value, md5_checksum) VALUES (?, ?, UNHEX(?))` // nolint:gosec // just test data, not hardcoded credentials
|
||||
_, err = db.Exec(insertNDESPasswordStmt, fleet.MDMAssetNDESPassword, ndesEncryptedPassword, md5ChecksumBytes(ndesEncryptedPassword))
|
||||
require.NoError(t, err, "failed to insert NDES SCEP Proxy password")
|
||||
|
||||
insertCAAssetsStmt := `INSERT INTO ca_config_assets (name, value, type) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?), (?, ?, ?)`
|
||||
_, err = db.Exec(insertCAAssetsStmt,
|
||||
digicertCA1Name, digicertCA1EncryptedPassword, fleet.CAConfigDigiCert,
|
||||
digicertCA2Name, digicertCA2EncryptedPassword, fleet.CAConfigDigiCert,
|
||||
customSCEPCA1Name, customSCEPCA1EncryptedChallenge, fleet.CAConfigCustomSCEPProxy,
|
||||
customSCEPCA2Name, customSCEPCA2EncryptedChallenge, fleet.CAConfigCustomSCEPProxy,
|
||||
)
|
||||
require.NoError(t, err, "failed to insert ca_config_assets")
|
||||
|
||||
_, err = db.Exec(
|
||||
`INSERT INTO app_config_json(json_value) VALUES(?) ON DUPLICATE KEY UPDATE json_value = VALUES(json_value)`,
|
||||
jsonBytes,
|
||||
)
|
||||
if err != nil {
|
||||
require.NoError(t, err, "failed to insert app_config_json")
|
||||
}
|
||||
// Apply current migration.
|
||||
applyNext(t, db)
|
||||
|
||||
type dbCertificateAuthority struct {
|
||||
fleet.CertificateAuthority
|
||||
// Digicert
|
||||
APITokenEncrypted []byte `db:"api_token_encrypted"`
|
||||
CertificateUserPrincipalNamesRaw []byte `db:"certificate_user_principal_names"`
|
||||
|
||||
// NDES SCEP Proxy
|
||||
PasswordEncrypted []byte `db:"password_encrypted"`
|
||||
|
||||
// Custom SCEP Proxy
|
||||
ChallengeEncrypted []byte `db:"challenge_encrypted"`
|
||||
|
||||
// Hydrant
|
||||
ClientSecretEncrypted []byte `db:"client_secret_encrypted"`
|
||||
}
|
||||
|
||||
cas := []dbCertificateAuthority{}
|
||||
stmt := `SELECT type, name, url, api_token_encrypted, profile_id, certificate_common_name, certificate_user_principal_names, certificate_seat_id, admin_url, username, password_encrypted, challenge_encrypted, client_id, client_secret_encrypted, created_at, updated_at
|
||||
FROM certificate_authorities`
|
||||
err = db.Select(&cas, stmt)
|
||||
|
||||
casFound := []string{}
|
||||
require.NoError(t, err, "failed to select certificate authorities")
|
||||
require.Len(t, cas, 5, "expected 5 certificate authorities")
|
||||
|
||||
for _, ca := range cas {
|
||||
if ca.CertificateUserPrincipalNamesRaw != nil {
|
||||
err = json.Unmarshal(ca.CertificateUserPrincipalNamesRaw, &ca.CertificateUserPrincipalNames)
|
||||
require.NoErrorf(t, err, "failed to unmarshal certificate user principal names for %s", ca.Name)
|
||||
}
|
||||
casFound = append(casFound, ca.Name)
|
||||
|
||||
// No Hydrant CAs in this test so these should be nil
|
||||
assert.Nil(t, ca.ClientID)
|
||||
assert.Nil(t, ca.ClientSecret)
|
||||
switch ca.Type {
|
||||
case "digicert":
|
||||
assert.Contains(t, []string{digicertCA1Name, digicertCA2Name}, ca.Name, "unexpected DigiCert CA name")
|
||||
expectedCA := digicertCAs[0]
|
||||
expectedAPIToken := digicertCA1EncryptedPassword
|
||||
if ca.Name == digicertCA2Name {
|
||||
expectedCA = digicertCAs[1]
|
||||
expectedAPIToken = digicertCA2EncryptedPassword
|
||||
}
|
||||
assert.Equal(t, expectedCA.URL, ca.URL)
|
||||
assert.Equal(t, expectedAPIToken, ca.APITokenEncrypted)
|
||||
require.NotNil(t, ca.ProfileID)
|
||||
assert.Equal(t, expectedCA.ProfileID, *ca.ProfileID)
|
||||
require.NotNil(t, ca.CertificateCommonName)
|
||||
assert.Equal(t, expectedCA.CertificateCommonName, *ca.CertificateCommonName)
|
||||
assert.Equal(t, expectedCA.CertificateUserPrincipalNames, ca.CertificateUserPrincipalNames)
|
||||
require.NotNil(t, ca.CertificateSeatID)
|
||||
assert.Equal(t, expectedCA.CertificateSeatID, *ca.CertificateSeatID)
|
||||
case "custom_scep_proxy":
|
||||
require.Contains(t, []string{customSCEPCA1Name, customSCEPCA2Name}, ca.Name, "unexpected Custom SCEP Proxy CA name")
|
||||
expectedCA := customSCEPProxyCAs[0]
|
||||
expectedChallenge := customSCEPCA1EncryptedChallenge
|
||||
if ca.Name == customSCEPCA2Name {
|
||||
expectedCA = customSCEPProxyCAs[1]
|
||||
expectedChallenge = customSCEPCA2EncryptedChallenge
|
||||
}
|
||||
assert.Equal(t, expectedCA.URL, ca.URL)
|
||||
assert.Equal(t, expectedChallenge, ca.ChallengeEncrypted)
|
||||
assert.Nil(t, ca.CertificateUserPrincipalNames)
|
||||
case "ndes_scep_proxy":
|
||||
assert.Equal(t, "DEFAULT_NDES_CA", ca.Name)
|
||||
require.NotNil(t, ca.AdminURL)
|
||||
assert.Equal(t, ndesCA.AdminURL, *ca.AdminURL)
|
||||
assert.Equal(t, ndesCA.URL, ca.URL)
|
||||
require.NotNil(t, ca.Username)
|
||||
assert.Equal(t, ndesCA.Username, *ca.Username)
|
||||
assert.Equal(t, ndesEncryptedPassword, ca.PasswordEncrypted)
|
||||
assert.Nil(t, ca.CertificateUserPrincipalNames)
|
||||
default:
|
||||
require.Failf(t, "unexpected certificate authority type", "type: %s, name: %s", ca.Type, ca.Name)
|
||||
}
|
||||
}
|
||||
require.ElementsMatch(t, []string{digicertCA1Name, digicertCA2Name, customSCEPCA1Name, customSCEPCA2Name, "DEFAULT_NDES_CA"}, casFound)
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,59 @@
|
||||
package fleet
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type CAConfigAssetType string
|
||||
|
||||
const (
|
||||
CAConfigNDES CAConfigAssetType = "ndes"
|
||||
CAConfigDigiCert CAConfigAssetType = "digicert"
|
||||
CAConfigCustomSCEPProxy CAConfigAssetType = "custom_scep_proxy"
|
||||
)
|
||||
|
||||
type CAConfigAsset struct {
|
||||
Name string `db:"name"`
|
||||
Value []byte `db:"value"`
|
||||
Type CAConfigAssetType `db:"type"`
|
||||
}
|
||||
|
||||
type CAType string
|
||||
|
||||
const (
|
||||
CATypeNDESSCEPProxy CAType = "ndes_scep_proxy"
|
||||
CATypeDigiCert CAType = "digicert"
|
||||
CATypeCustomSCEPProxy CAType = "custom_scep_proxy"
|
||||
CATypeHydrant CAType = "hydrant"
|
||||
)
|
||||
|
||||
type CertificateAuthority struct {
|
||||
ID uint `json:"id" db:"id"`
|
||||
Type string `json:"type" db:"type"`
|
||||
|
||||
// common
|
||||
Name string `json:"name" db:"name"`
|
||||
URL string `json:"url" db:"url"`
|
||||
|
||||
// Digicert
|
||||
APIToken *string `json:"api_token,omitempty" db:"-"`
|
||||
ProfileID *string `json:"profile_id,omitempty" db:"profile_id"`
|
||||
CertificateCommonName *string `json:"certificate_common_name,omitempty" db:"certificate_common_name"`
|
||||
CertificateUserPrincipalNames []string `json:"certificate_user_principal_names,omitempty" db:"-"`
|
||||
CertificateSeatID *string `json:"certificate_seat_id,omitempty" db:"certificate_seat_id"`
|
||||
|
||||
// NDES SCEP Proxy
|
||||
AdminURL *string `json:"admin_url,omitempty" db:"admin_url"`
|
||||
Username *string `json:"username,omitempty" db:"username"`
|
||||
Password *string `json:"password,omitempty" db:"-"`
|
||||
|
||||
// Custom SCEP Proxy
|
||||
Challenge *string `json:"challenge,omitempty" db:"-"`
|
||||
|
||||
// Hydrant
|
||||
ClientID *string `json:"client_id,omitempty" db:"client_id"`
|
||||
ClientSecret *string `json:"client_secret,omitempty" db:"-"`
|
||||
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
@@ -805,20 +805,6 @@ func (m MDMConfigAsset) Copy() MDMConfigAsset {
|
||||
return clone
|
||||
}
|
||||
|
||||
type CAConfigAssetType string
|
||||
|
||||
const (
|
||||
CAConfigNDES CAConfigAssetType = "ndes"
|
||||
CAConfigDigiCert CAConfigAssetType = "digicert"
|
||||
CAConfigCustomSCEPProxy CAConfigAssetType = "custom_scep_proxy"
|
||||
)
|
||||
|
||||
type CAConfigAsset struct {
|
||||
Name string `db:"name"`
|
||||
Value []byte `db:"value"`
|
||||
Type CAConfigAssetType `db:"type"`
|
||||
}
|
||||
|
||||
// MDMPlatform returns "darwin" or "windows" as MDM platforms
|
||||
// derived from a host's platform (hosts.platform field).
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user