@@ -43,6 +43,7 @@ const (
4343 Master PtpRole = 1
4444 Slave PtpRole = 0
4545)
46+ const PTP_SEC_FOLDER = "/etc/ptp-secret-mount/"
4647
4748// log is for logging in this package.
4849var ptpconfiglog = logf .Log .WithName ("ptpconfig-resource" )
@@ -70,11 +71,6 @@ type Ptp4lConf struct {
7071 sections map [string ]Ptp4lConfSection
7172}
7273
73- // PopulatePtp4lConf parses the ptp4l configuration
74- func (p * Ptp4lConf ) PopulatePtp4lConf (config * string , ptp4lopts * string ) error {
75- return p .populatePtp4lConf (config , ptp4lopts )
76- }
77-
7874// GetOption retrieves an option value from a specific section
7975func (p * Ptp4lConf ) GetOption (section , key string ) string {
8076 if sec , ok := p .sections [section ]; ok {
@@ -85,7 +81,7 @@ func (p *Ptp4lConf) GetOption(section, key string) string {
8581 return ""
8682}
8783
88- func (output * Ptp4lConf ) populatePtp4lConf (config * string , ptp4lopts * string ) error {
84+ func (output * Ptp4lConf ) PopulatePtp4lConf (config * string , ptp4lopts * string ) error {
8985 var string_config string
9086 if config != nil {
9187 string_config = * config
@@ -130,7 +126,7 @@ func (r *PtpConfig) validate() error {
130126
131127 for _ , profile := range profiles {
132128 conf := & Ptp4lConf {}
133- conf .populatePtp4lConf (profile .Ptp4lConf , profile .Ptp4lOpts )
129+ conf .PopulatePtp4lConf (profile .Ptp4lConf , profile .Ptp4lOpts )
134130
135131 // Validate that interface field only set in ordinary clock
136132 if profile .Interface != nil && * profile .Interface != "" {
@@ -216,100 +212,64 @@ func (r *PtpConfig) validate() error {
216212 }
217213 }
218214
219- // Validate secret-related settings for this profile
220- if profile .PtpSecretName != nil && * profile .PtpSecretName != "" {
221- sppValue , err := getSppFromPtp4lConf (conf )
222- if err != nil {
223- return fmt .Errorf ("failed to get spp value from ptp4lConf: %w" , err )
224- }
225- if err := validateSecretExists (sppValue , * profile .PtpSecretName ); err != nil {
226- return fmt .Errorf ("failed to validate secret from profile: %w" , err )
227- }
228- saFilePath , err := getSaFileFromPtp4lConf (conf )
229- if err != nil {
230- return fmt .Errorf ("failed to get sa file path from ptp4lConf: %w" , err )
231- }
232- if err := validateSaFileSecretConflicts (saFilePath , * profile .PtpSecretName , r .Name , r .Namespace ); err != nil {
233- return fmt .Errorf ("failed to validate secret conflicts from profile: %w" , err )
234- }
215+ // validate secret-related settings for this profile
216+ saFilePath , err := getSaFileFromPtp4lConf (conf )
217+ if err != nil {
218+ return fmt .Errorf ("failed to get sa file path from ptp4lConf: %w" , err )
235219 }
236- }
237- return nil
238- }
239-
240- // validateSecretConflicts checks if a single profile's sa_file + secret combination
241- // conflicts with any existing PtpConfigs in the openshift-ptp namespace
242- func validateSaFileSecretConflicts (saFilePath string , secretName string , name string , namespace string ) error {
243- if webhookClient == nil {
244- ptpconfiglog .Info ("webhook client not initialized, skipping cross-PtpConfig validation" )
245- return nil
246- }
247-
248- // List all existing PtpConfigs in openshift-ptp namespace
249- ptpConfigList := & PtpConfigList {}
250- if err := webhookClient .List (context .Background (), ptpConfigList , & client.ListOptions {
251- Namespace : "openshift-ptp" ,
252- }); err != nil {
253- ptpconfiglog .Error (err , "failed to list PtpConfigs for validation" )
254- // Don't block creation if we can't list - fail open
255- return nil
256- }
257-
258- // Check each existing PtpConfig for conflicts
259- for _ , existingConfig := range ptpConfigList .Items {
260- // Skip checking against ourselves (for updates)
261- if existingConfig .Name == name && existingConfig .Namespace == namespace {
262- continue
220+ if err := validateSaFile (saFilePath ); err != nil {
221+ return fmt .Errorf ("failed to validate sa file: %w" , err )
263222 }
264-
265- // Check each profile in the existing config
266- for _ , existingProfile := range existingConfig .Spec .Profile {
267- if existingProfile .PtpSecretName == nil || * existingProfile .PtpSecretName == "" {
268- continue
269- }
270- if existingProfile .Ptp4lConf == nil {
271- continue
272- }
273-
274- existingConf := & Ptp4lConf {}
275- if err := existingConf .populatePtp4lConf (existingProfile .Ptp4lConf , existingProfile .Ptp4lOpts ); err != nil {
276- continue
277- }
278- globalSection , exists := existingConf .sections ["[global]" ]
279- if ! exists {
280- continue
281- }
282- existingSaFile , exists := globalSection .options ["sa_file" ]
283- if ! exists {
284- continue
285- }
286- // Check if same sa_file as our profile and different secret
287- if existingSaFile == saFilePath && * existingProfile .PtpSecretName != secretName {
288- return fmt .Errorf ("sa_file '%s' conflict: PtpConfig '%s' already uses secret '%s' with this sa_file path, but this profile tries to use secret '%s'. All PtpConfigs using the same sa_file must reference the same secret" ,
289- saFilePath , existingConfig .Name , * existingProfile .PtpSecretName , secretName )
290- }
223+ secretName := GetSecretNameFromSaFilePath (saFilePath )
224+ sppValue , err := getSppFromPtp4lConf (conf )
225+ if err != nil {
226+ return fmt .Errorf ("failed to get spp value from ptp4lConf: %w" , err )
227+ }
228+ if err := validateSecretForSPP (sppValue , secretName ); err != nil {
229+ return fmt .Errorf ("failed to validate secret from profile: %w" , err )
291230 }
292- }
293231
232+ }
294233 return nil
295234}
296235
297- // validateSecretExists checks that a single profile's ptpSecretName references an existing secret
298- func validateSecretExists ( sppValue string , secretName string ) error {
236+ // checking if the secret exists in the openshift-ptp namespace
237+ func isValidSecretName ( secretName string ) * corev1. Secret {
299238 if webhookClient == nil {
300239 ptpconfiglog .Info ("webhook client not initialized, skipping secret existence validation" )
301240 return nil
302241 }
303-
304- // Try to get the secret from openshift-ptp namespace
305242 secret := & corev1.Secret {}
306243 err := webhookClient .Get (context .Background (), types.NamespacedName {
307244 Namespace : "openshift-ptp" ,
308245 Name : secretName ,
309246 }, secret )
310-
311247 if err != nil {
312- return fmt .Errorf ("failed to get secret %q: %w" , secretName , err )
248+ return nil
249+ }
250+ return secret
251+ }
252+
253+ // GetSecretNameFromSaFilePath extracts the secret name from the sa_file path
254+ func GetSecretNameFromSaFilePath (sa_file string ) string {
255+ path := strings .TrimPrefix (sa_file , PTP_SEC_FOLDER )
256+ index := strings .Index (path , "/" )
257+ return path [:index ]
258+ }
259+
260+ // GetSecretKeyFromSaFilePath extracts the secret key from the sa_file path
261+ func GetSecretKeyFromSaFilePath (sa_file string ) string {
262+ path := strings .TrimPrefix (sa_file , PTP_SEC_FOLDER )
263+ index := strings .Index (path , "/" )
264+ return path [index + 1 :]
265+ }
266+
267+ // validateSecretExists checks that a single profile's ptpSecretName references an existing secret
268+ func validateSecretForSPP (sppValue string , secretName string ) error {
269+
270+ secret := isValidSecretName (secretName )
271+ if secret == nil {
272+ return fmt .Errorf ("secret %s does not exist" , secretName )
313273 }
314274
315275 // Validate SPP (Security Parameter Profile) if specified
@@ -349,6 +309,38 @@ func getSaFileFromPtp4lConf(conf *Ptp4lConf) (string, error) {
349309 return saFileValue , nil
350310}
351311
312+ // validateSaFile checks that the sa_file path is valid with prefix PTP_SEC_FOLDER
313+ // next directory must be a valid secret name, e.g. PTP_SEC_FOLDER/secret_name/secret_key
314+ // check that secret_key exists in the secret_name secret
315+ func validateSaFile (saFilePath string ) error {
316+ if ! strings .HasPrefix (saFilePath , PTP_SEC_FOLDER ) {
317+ return fmt .Errorf ("sa_file path '%s' is invalid; must start with '%s'" , saFilePath , PTP_SEC_FOLDER )
318+ }
319+ path := strings .TrimPrefix (saFilePath , PTP_SEC_FOLDER )
320+ index := strings .Index (path , "/" )
321+ if index == - 1 || index == len (path )- 1 {
322+ return fmt .Errorf ("sa_file path '%s' is incomplete; must contain a secret key" , saFilePath )
323+ }
324+ secretName := path [:index ]
325+ if secretName == "" {
326+ return fmt .Errorf ("sa_file path '%s' is invalid; must contain a secret name" , saFilePath )
327+ }
328+ secret := isValidSecretName (secretName )
329+ if secret == nil {
330+ return fmt .Errorf ("sa_file path '%s' has invalid secret name '%s'" , saFilePath , secretName )
331+ }
332+ keyCandidate := path [index + 1 :]
333+ return validateKeyInSecret (secret , keyCandidate )
334+ }
335+
336+ // this function will recieve a secret and a key candidate and check if the key is part of the secret
337+ func validateKeyInSecret (secret * corev1.Secret , keyCandidate string ) error {
338+ if _ , exists := secret .Data [keyCandidate ]; ! exists {
339+ return fmt .Errorf ("key '%s' is not part of the secret" , keyCandidate )
340+ }
341+ return nil
342+ }
343+
352344// validateSppInSecret checks that the spp value in ptp4lConf exists in the referenced secret
353345func validateSppInSecret (sppValue string , secret * corev1.Secret ) error {
354346 for key , value := range secret .Data {
@@ -435,7 +427,7 @@ func GetInterfaces(config PtpConfig, mode PtpRole) (interfaces []string) {
435427 }
436428 conf := & Ptp4lConf {}
437429 var dummy * string
438- err := conf .populatePtp4lConf (config .Spec .Profile [0 ].Ptp4lConf , dummy )
430+ err := conf .PopulatePtp4lConf (config .Spec .Profile [0 ].Ptp4lConf , dummy )
439431 if err != nil {
440432 logrus .Warnf ("ptp4l conf parsing failed, err=%s" , err )
441433 }
0 commit comments