// ReadAdmissionConfiguration reads the admission configuration at the specified path. // It returns the loaded admission configuration if the input file aligns with the required syntax. // If it does not align with the provided syntax, it returns a default configuration for the enumerated // set of pluginNames whose config location references the specified configFilePath. // It does this to preserve backward compatibility when admission control files were opaque. // It returns an error if the file did not exist. func ReadAdmissionConfiguration(pluginNames []string, configFilePath string) (admission.ConfigProvider, error) { if configFilePath == "" { return configProvider{config: &componentconfig.AdmissionConfiguration{}}, nil } // a file was provided, so we just read it. data, err := ioutil.ReadFile(configFilePath) if err != nil { return nil, fmt.Errorf("unable to read admission control configuration from %q [%v]", configFilePath, err) } decoder := api.Codecs.UniversalDecoder() decodedObj, err := runtime.Decode(decoder, data) // we were able to decode the file successfully if err == nil { decodedConfig, ok := decodedObj.(*componentconfig.AdmissionConfiguration) if !ok { return nil, fmt.Errorf("unexpected type: %T", decodedObj) } baseDir := path.Dir(configFilePath) for i := range decodedConfig.Plugins { if decodedConfig.Plugins[i].Path == "" { continue } // we update relative file paths to absolute paths absPath, err := makeAbs(decodedConfig.Plugins[i].Path, baseDir) if err != nil { return nil, err } decodedConfig.Plugins[i].Path = absPath } return configProvider{config: decodedConfig}, nil } // we got an error where the decode wasn't related to a missing type if !(runtime.IsMissingVersion(err) || runtime.IsMissingKind(err) || runtime.IsNotRegisteredError(err)) { return nil, err } // convert the legacy format to the new admission control format // in order to preserve backwards compatibility, we set plugins that // previously read input from a non-versioned file configuration to the // current input file. legacyPluginsWithUnversionedConfig := sets.NewString("ImagePolicyWebhook", "PodNodeSelector") externalConfig := &componentconfigv1alpha1.AdmissionConfiguration{} for _, pluginName := range pluginNames { if legacyPluginsWithUnversionedConfig.Has(pluginName) { externalConfig.Plugins = append(externalConfig.Plugins, componentconfigv1alpha1.AdmissionPluginConfiguration{ Name: pluginName, Path: configFilePath}) } } api.Scheme.Default(externalConfig) internalConfig := &componentconfig.AdmissionConfiguration{} if err := api.Scheme.Convert(externalConfig, internalConfig, nil); err != nil { return nil, err } return configProvider{config: internalConfig}, nil }
// TODO: Have policies be created via an API call and stored in REST storage. func NewFromFile(path string) (policyList, error) { // File format is one map per line. This allows easy concatentation of files, // comments in files, and identification of errors by line number. file, err := os.Open(path) if err != nil { return nil, err } defer file.Close() scanner := bufio.NewScanner(file) pl := make(policyList, 0) decoder := api.Codecs.UniversalDecoder() i := 0 unversionedLines := 0 for scanner.Scan() { i++ p := &api.Policy{} b := scanner.Bytes() // skip comment lines and blank lines trimmed := strings.TrimSpace(string(b)) if len(trimmed) == 0 || strings.HasPrefix(trimmed, "#") { continue } decodedObj, _, err := decoder.Decode(b, nil, nil) if err != nil { if !(runtime.IsMissingVersion(err) || runtime.IsMissingKind(err) || runtime.IsNotRegisteredError(err)) { return nil, policyLoadError{path, i, b, err} } unversionedLines++ // Migrate unversioned policy object oldPolicy := &v0.Policy{} if err := runtime.DecodeInto(decoder, b, oldPolicy); err != nil { return nil, policyLoadError{path, i, b, err} } if err := api.Scheme.Convert(oldPolicy, p, nil); err != nil { return nil, policyLoadError{path, i, b, err} } pl = append(pl, p) continue } decodedPolicy, ok := decodedObj.(*api.Policy) if !ok { return nil, policyLoadError{path, i, b, fmt.Errorf("unrecognized object: %#v", decodedObj)} } pl = append(pl, decodedPolicy) } if unversionedLines > 0 { glog.Warningf("Policy file %s contained unversioned rules. See docs/admin/authorization.md#abac-mode for ABAC file format details.", path) } if err := scanner.Err(); err != nil { return nil, policyLoadError{path, -1, nil, err} } return pl, nil }