parseExternalCA parses an external CA specification from the command line, such as protocol=cfssl,url=https://example.com.
(caSpec string)
| 159 | // parseExternalCA parses an external CA specification from the command line, |
| 160 | // such as protocol=cfssl,url=https://example.com. |
| 161 | func parseExternalCA(caSpec string) (*swarm.ExternalCA, error) { |
| 162 | csvReader := csv.NewReader(strings.NewReader(caSpec)) |
| 163 | fields, err := csvReader.Read() |
| 164 | if err != nil { |
| 165 | return nil, err |
| 166 | } |
| 167 | |
| 168 | externalCA := swarm.ExternalCA{ |
| 169 | Options: make(map[string]string), |
| 170 | } |
| 171 | |
| 172 | var ( |
| 173 | hasProtocol bool |
| 174 | hasURL bool |
| 175 | ) |
| 176 | |
| 177 | for _, field := range fields { |
| 178 | key, value, ok := strings.Cut(field, "=") |
| 179 | if !ok { |
| 180 | return nil, fmt.Errorf("invalid field '%s' must be a key=value pair", field) |
| 181 | } |
| 182 | |
| 183 | // TODO(thaJeztah): these options should not be case-insensitive. |
| 184 | switch strings.ToLower(key) { |
| 185 | case "protocol": |
| 186 | hasProtocol = true |
| 187 | if strings.ToLower(value) == string(swarm.ExternalCAProtocolCFSSL) { |
| 188 | externalCA.Protocol = swarm.ExternalCAProtocolCFSSL |
| 189 | } else { |
| 190 | return nil, fmt.Errorf("unrecognized external CA protocol %s", value) |
| 191 | } |
| 192 | case "url": |
| 193 | hasURL = true |
| 194 | externalCA.URL = value |
| 195 | case "cacert": |
| 196 | cacontents, err := os.ReadFile(value) |
| 197 | if err != nil { |
| 198 | return nil, fmt.Errorf("unable to read CA cert for external CA: %w", err) |
| 199 | } |
| 200 | if pemBlock, _ := pem.Decode(cacontents); pemBlock == nil { |
| 201 | return nil, errors.New("CA cert for external CA must be in PEM format") |
| 202 | } |
| 203 | externalCA.CACert = string(cacontents) |
| 204 | default: |
| 205 | externalCA.Options[key] = value |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | if !hasProtocol { |
| 210 | return nil, errors.New("the external-ca option needs a protocol= parameter") |
| 211 | } |
| 212 | if !hasURL { |
| 213 | return nil, errors.New("the external-ca option needs a url= parameter") |
| 214 | } |
| 215 | |
| 216 | return &externalCA, nil |
| 217 | } |
| 218 |