diff --git a/cmd/argocd/commands/cert.go b/cmd/argocd/commands/cert.go index 1a647338a8..de9ac59854 100644 --- a/cmd/argocd/commands/cert.go +++ b/cmd/argocd/commands/cert.go @@ -174,18 +174,20 @@ func NewCertAddSSHCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command } for _, knownHostsEntry := range sshKnownHostsLists { - hostname, certSubType, certData, err := certutil.TokenizeSSHKnownHostsEntry(knownHostsEntry) + _, certSubType, certData, err := certutil.TokenizeSSHKnownHostsEntry(knownHostsEntry) errors.CheckError(err) - _, _, err = certutil.KnownHostsLineToPublicKey(knownHostsEntry) + hostnameList, _, err := certutil.KnownHostsLineToPublicKey(knownHostsEntry) errors.CheckError(err) - certificate := appsv1.RepositoryCertificate{ - ServerName: hostname, - CertType: "ssh", - CertSubType: certSubType, - CertData: certData, + // Each key could be valid for multiple hostnames + for _, hostname := range hostnameList { + certificate := appsv1.RepositoryCertificate{ + ServerName: hostname, + CertType: "ssh", + CertSubType: certSubType, + CertData: certData, + } + certificates = append(certificates, certificate) } - - certificates = append(certificates, certificate) } certList := &appsv1.RepositoryCertificateList{Items: certificates} diff --git a/ui/src/app/settings/components/certs-list/certs-list.tsx b/ui/src/app/settings/components/certs-list/certs-list.tsx index 2633f9598f..c81571d11e 100644 --- a/ui/src/app/settings/components/certs-list/certs-list.tsx +++ b/ui/src/app/settings/components/certs-list/certs-list.tsx @@ -223,13 +223,19 @@ export class CertsList extends React.Component> { // the first place. const subType = knownHosts[1].match(/^(ssh\-[a-z0-9]+|ecdsa-[a-z0-9\-]+)$/gi); if (subType != null) { - knownHostEntries = knownHostEntries.concat({ - serverName: knownHosts[0], - certType: 'ssh', - certSubType: knownHosts[1], - certData: btoa(knownHosts[2]), - certInfo: '' - }); + // Key could be valid for multiple hosts + const hostnames = knownHosts[0].split(','); + for (const hostname of hostnames) { + knownHostEntries = knownHostEntries.concat({ + serverName: hostname, + certType: 'ssh', + certSubType: knownHosts[1], + certData: btoa(knownHosts[2]), + certInfo: '' + }); + } + } else { + throw new Error('Invalid SSH subtype: ' + subType); } } } diff --git a/util/cert/cert.go b/util/cert/cert.go index 6f00a09e99..dbd5a74676 100644 --- a/util/cert/cert.go +++ b/util/cert/cert.go @@ -67,6 +67,10 @@ const ( // Regular expression that matches a valid hostname var validHostNameRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*(\.){0,1}$`) +// Regular expression that matches all kind of IPv6 addresses +// See https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses +var validIPv6Regexp = regexp.MustCompile(`(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`) + // Regular expression that matches a valid FQDN var validFQDNRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]))*(\.){1}$`) @@ -74,7 +78,7 @@ var validFQDNRegexp = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{ // If fqdn is true, given string must also be a FQDN representation. func IsValidHostname(hostname string, fqdn bool) bool { if !fqdn { - return validHostNameRegexp.Match([]byte(hostname)) + return validHostNameRegexp.Match([]byte(hostname)) || validIPv6Regexp.Match([]byte(hostname)) } else { return validFQDNRegexp.Match([]byte(hostname)) }