Skip to content
Snippets Groups Projects
Select Git revision
  • 7baef30a867d40e6dbc9bdbfe5c8e674199e88fb
  • develop default
  • master protected
  • feature/frontend-tests
  • 0.107
  • 0.106
  • 0.105
  • 0.104
  • 0.103
  • 0.102
  • 0.101
  • 0.100
  • 0.99
  • 0.98
  • 0.97
  • 0.96
  • 0.95
  • 0.94
  • 0.93
  • 0.92
  • 0.91
  • 0.90
  • 0.89
  • 0.88
24 results

test_dump_survey_model.py

Blame
  • main.go 14.70 KiB
    package main
    
    import (
    	"crypto/tls"
    	"crypto/x509"
    	"encoding/pem"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"os"
    	"os/user"
    	"path/filepath"
    	"runtime"
    	"strconv"
    	"strings"
    	"time"
    
    	"github.com/docopt/docopt-go"
    	"github.com/go-ini/ini"
    	"github.com/tidwall/gjson"
    )
    
    const errMsg string = "[ERR]"
    const infoMsg string = "[INFO]"
    
    var (
    	appVersion                string
    	buildTime                 string
    	CertBase                  string
    	KeyBase                   string
    	GroupName                 string
    	GroupID                   int
    	RedisBaseURL              string
    	VaultBaseURL              string
    	VaultURL                  string
    	RedisCertURL              string
    	RedisCAURL                string
    	RedisFullChainURL         string
    	certificateDestination    string
    	fullchainDestination      string
    	keyDestination            string
    	caDestination             string
    	Type                      string
    	tmpCertificateDestination string
    	tmpFullchainDestination   string
    	tmpCaDestination          string
    	tmpKeyDestination         string
    	certTmpDir                string
    	key                       *x509.Certificate
    	cert                      *x509.Certificate
    )
    
    // app clean and exit
    func appExit(status int) {
    	if runtime.GOOS == "windows" {
    		certTmpDir = "C:\\tmp\\acme-downloader\\"
    	} else {
    		certTmpDir = "/tmp/acme-downloader"
    	}
    	err := os.RemoveAll(certTmpDir)
    	if err != nil {
    		fmt.Printf("%v could not delete temporary directory: %v\n", errMsg, err)
    	}
    	os.Exit(status)
    }
    
    // check certificates
    func checkCertificates(dnsname string, certificate string, fullchain string, ca string, key string, days int, fail bool) bool {
    
    	Seconds := days * 86400
    	daysNumber := time.Now().Local().Add(time.Second * time.Duration(Seconds))
    
    	certPEM, err := ioutil.ReadFile(certificate)
    	if err != nil {
    		if fail == true {
    			fmt.Printf("%v could not access certificate %v\n", errMsg, err)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    
    	certFullchainPEM, err := ioutil.ReadFile(fullchain)
    	if err != nil {
    		if fail == true {
    			fmt.Printf("%v could not access full chain %v\n", errMsg, err)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    
    	rootPEM, err := ioutil.ReadFile(ca)
    	if err != nil {
    		if fail == true {
    			fmt.Printf("%v could not access full CA %v\n", errMsg, err)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    
    	roots := x509.NewCertPool()
    	ok := roots.AppendCertsFromPEM([]byte(rootPEM))
    	if !ok {
    		if fail == true {
    			fmt.Printf("%v failed to parse root certificate\n", errMsg)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    
    	block, _ := pem.Decode([]byte(certPEM))
    	if block == nil {
    		if fail == true {
    			fmt.Printf("%v failed to parse certificate PEM\n", errMsg)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    
    	cert, err := x509.ParseCertificate(block.Bytes)
    	if err != nil {
    		if fail == true {
    			fmt.Printf("%v failed to parse certificate %v\n", errMsg, err)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    
    	fullchainBlock, _ := pem.Decode([]byte(certFullchainPEM))
    	if fullchainBlock == nil {
    		if fail == true {
    			fmt.Printf("%v failed to parse full chain PEM\n", errMsg)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    	fullchainCert, fullchainErr := x509.ParseCertificate(fullchainBlock.Bytes)
    	if fullchainErr != nil {
    		if fail == true {
    			fmt.Printf("%v failed to parse full chain %v\n", errMsg, fullchainErr)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    
    	opts := x509.VerifyOptions{
    		Roots:         roots,
    		DNSName:       dnsname,
    		CurrentTime:   daysNumber,
    		Intermediates: x509.NewCertPool(),
    	}
    
    	if _, err := cert.Verify(opts); err != nil {
    		if fail == true {
    			fmt.Printf("%v failed to parse certificate %v\n", errMsg, err.Error())
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    	if _, fullchainErr := fullchainCert.Verify(opts); fullchainErr != nil {
    		if fail == true {
    			fmt.Printf("%v failed to parse full chain %v\n", errMsg, err.Error())
    		} else {
    			return false
    		}
    	}
    	return true
    }
    
    // check if the private key matches the publick key
    func checkPrivkey(privkey string, pubkey string, fail bool) bool {
    	_, errFileExist := os.Stat(privkey)
    	if os.IsNotExist(errFileExist) {
    		fmt.Printf("%v could not access the private key %v\n", errMsg, privkey)
    		appExit(255)
    	}
    	_, err := tls.LoadX509KeyPair(pubkey, privkey)
    	if fail == true {
    		if err != nil {
    			fmt.Printf("%v the private key %v does not match the the public certificate %v\n", errMsg, privkey, pubkey)
    			appExit(255)
    		} else {
    			return false
    		}
    	}
    	return true
    }
    
    // get redis key
    func GetRedisKey(redisurl string, redistoken string) string {
    	client := &http.Client{}
    	req, err := http.NewRequest("GET", redisurl, nil)
    	if err != nil {
    		fmt.Printf("%v Fail to read %v: %v\n", errMsg, redisurl, err)
    		appExit(255)
    	}
    	req.SetBasicAuth("redis", redistoken)
    	resp, err := client.Do(req)
    	body, err := ioutil.ReadAll(resp.Body)
    	if resp.StatusCode < 200 || resp.StatusCode > 299 {
    		fmt.Printf("%v Fail to fetch %v\n", errMsg, redisurl)
    		appExit(255)
    	}
    	defer resp.Body.Close()
    	if err != nil {
    		fmt.Printf("%v Fail to read %v: %v\n", errMsg, redisurl, err)
    		appExit(255)
    	}
    	return fmt.Sprintf(string(body))
    }
    
    // get Vault key
    func GetVaultKey(vaulturl string, vaulttoken string) string {
    	vaultClient := &http.Client{}
    	req, err := http.NewRequest("GET", vaulturl, nil)
    	if err != nil {
    		fmt.Printf("%v Fail to read %v: %v\n", errMsg, vaulturl, err)
    		appExit(255)
    	}
    	req.Header.Add("X-vault-token", vaulttoken)
    	resp, err := vaultClient.Do(req)
    	body, err := ioutil.ReadAll(resp.Body)
    	if resp.StatusCode < 200 || resp.StatusCode > 299 {
    		fmt.Printf("%v Fail to fetch %v\n", errMsg, vaulturl)
    		appExit(255)
    	}
    	defer resp.Body.Close()
    	if err != nil {
    		fmt.Printf("%v Fail to read %v: %v\n", errMsg, vaulturl, err)
    		appExit(255)
    	}
    	return gjson.Get(string(body), "data.value").String()
    }
    
    // create directory structure and write certificate to file
    func WriteToFile(content string, destination string, filemode os.FileMode) {
    	baseDir := filepath.Dir(destination)
    	if _, err := os.Stat(baseDir); os.IsNotExist(err) {
    		os.MkdirAll(baseDir, 0755)
    	}
    
    	file, err := os.OpenFile(destination, os.O_WRONLY|os.O_CREATE, filemode)
    	if err != nil {
    		fmt.Printf("%v %v cannot be created\n", errMsg, destination)
    		appExit(255)
    	}
    
    	fmt.Fprintf(file, "%v\n", content)
    	file.Close()
    }
    
    // move temp file to destination
    func moveFile(source string, destination string, groupid int, filemode os.FileMode, dirmode os.FileMode) {
    	baseDir := filepath.Dir(destination)
    	if _, err := os.Stat(baseDir); os.IsNotExist(err) {
    		os.MkdirAll(baseDir, 0755)
    	}
    	err := os.Rename(source, destination)
    	if err != nil {
    		fmt.Printf("%v Fail to install %v: %v\n", errMsg, destination, err)
    		appExit(255)
    	}
    	if runtime.GOOS != "windows" {
    		err = os.Chown(destination, 0, groupid)
    		if err != nil {
    			fmt.Printf("%v Changing file owner to %v", errMsg, groupid)
    			appExit(255)
    		}
    	}
    	fmt.Printf("%v installed: %v\n", infoMsg, destination)
    }
    
    // ReadOSRelease from /etc/os-release
    func ReadOSRelease(configfile string) map[string]string {
    	ConfigParams := make(map[string]string)
    	cfg, err := ini.Load(configfile)
    	if err != nil {
    		ConfigParams["ID"] = "unknown"
    	} else {
    		ConfigParams["ID"] = cfg.Section("").Key("ID").String()
    	}
    
    	return ConfigParams
    }
    
    func main() {
    
    	OSInfo := ReadOSRelease("/etc/os-release")
    	OSRelease := OSInfo["ID"]
    	if OSRelease == "centos" || OSRelease == "rhel" {
    		CertBase = "/etc/pki/tls/certs"
    		KeyBase = "/etc/pki/tls/private"
    		GroupName = "root"
    	} else if OSRelease == "ubuntu" || OSRelease == "debian" {
    		CertBase = "/etc/ssl/certs"
    		KeyBase = "/etc/ssl/private"
    		GroupName = "ssl-cert"
    	} else if OSRelease == "arch" {
    		CertBase = "/etc/ssl/certs"
    		KeyBase = "/etc/ssl/private"
    		GroupName = "root"
    	} else if OSRelease == "unknown" {
    		if runtime.GOOS == "windows" {
    			CertBase = "C:\\ACME\\certificates"
    			KeyBase = "C:\\ACME\\private"
    			GroupName = "root"
    		} else {
    			CertBase = "/etc/acme/certs"
    			KeyBase = "/etc/acme/private"
    			GroupName = "root"
    		}
    	}
    
    	usage := fmt.Sprintf(`ACME Downloader:
      - fetches and stores a given Certificate, Full Chain, CA and Private Key
    
    Usage:
      acme-downloader --redis-token=REDISTOKEN --vault-token=VAULTTOKEN --cert-name=CERTNAME --team-name=TEAMNAME [--silent] [--days=DAYS] [--type=TYPE] [--cert-destination=CERTDESTINATION] [--fullchain-destination=FULLCHAINDESTINATION] [--key-destination=KEYDESTINATION] [--ca-destination=CADESTINATION] [--wildcard]
      acme-downloader -h | --help
      acme-downloader -v | --version
      acme-downloader -b | --build
    
    Options:
      -h --help                                     Show this screen
      -v --version                                  Print version information and exit
      -b --build                                    Print version and build information and exit
      --redis-token=REDISTOKEN                      Redis access token
      --vault-token=VAULTTOKEN                      Vault access token
      --cert-name=CERTNAME                          Certificate name
      --team-name=TEAMNAME                          Team name: swd, it, ne, ti...
      --days=DAYS                                   Days before expiration [default: 30]
      --type=TYPE                                   Type, EV or OV [default: EV]
      --cert-destination=CERTDESTINATION            Cert Destination [default: %v/<cert-name>.crt]
      --fullchain-destination=FULLCHAINDESTINATION  Full Chain Destination[default: %v/<cert-name>_fullchain.crt]
      --key-destination=KEYDESTINATION              Key Destination [default: %v/<cert-name>.key]
      --ca-destination=CADESTINATION                CA Destination [default: %v/COMODO_<type>.crt]
      --wildcard                                    The certificate type is wildcard
    `, CertBase, CertBase, KeyBase, CertBase)
    
    	arguments, _ := docopt.Parse(usage, nil, true, appVersion, false)
    
    	if arguments["--build"] == true {
    		fmt.Printf("acme-downloader version: %v, built on: %v\n", appVersion, buildTime)
    		appExit(0)
    	}
    
    	if runtime.GOOS == "windows" {
    		tmpCertificateDestination = "C:\\tmp\\acme-downloader\\cert\\amce_cert.pem"
    		tmpFullchainDestination = "C:\\tmp\\acme-downloader\\cert\\amce_fullchain.pem"
    		tmpCaDestination = "C:\\tmp\\acme-downloader\\cert\\amce_ca.pem"
    		tmpKeyDestination = "C:\\tmp\\acme-downloader\\key\\amce_key.pem"
    		GroupID = 0 // just a fake one
    	} else {
    		tmpCertificateDestination = "/tmp/acme-downloader/cert/amce_cert.pem"
    		tmpFullchainDestination = "/tmp/acme-downloader/cert/amce_fullchain.pem"
    		tmpCaDestination = "/tmp/acme-downloader/cert/amce_ca.pem"
    		tmpKeyDestination = "/tmp/acme-downloader/key/amce_key.pem"
    		group, groupErr := user.LookupGroup(GroupName)
    		if groupErr != nil {
    			fmt.Printf("%v Fail looking up %v user user info\n", errMsg, GroupName)
    			appExit(255)
    		}
    		GroupID, _ = strconv.Atoi(group.Gid)
    	}
    
    	VaultToken := arguments["--vault-token"].(string)
    	CertName := arguments["--cert-name"].(string)
    	CertNameUnderscored := strings.Replace(CertName, ".", "_", -1)
    	TeamName := arguments["--team-name"].(string)
    	RedisToken := arguments["--redis-token"].(string)
    	Type = arguments["--type"].(string)
    	DayString := arguments["--days"].(string)
    	Days, daysErr := strconv.Atoi(DayString)
    	if daysErr != nil {
    		fmt.Printf("%v Days mut be an integer\n", errMsg)
    		appExit(255)
    	}
    	RedisBaseURL = "https://redis.geant.org/GET"
    	VaultBaseURL = "https://vault.geant.org/v1"
    	if arguments["--wildcard"] == true {
    		VaultURL = fmt.Sprintf("%v/%v/common/vault_sectigo_ov_wildcard_%v_key", VaultBaseURL, TeamName, CertNameUnderscored)
    		RedisCertURL = fmt.Sprintf("%v/%v:common:redis_sectigo_ov_%v_pem.txt", RedisBaseURL, TeamName, CertNameUnderscored)
    		RedisCAURL = fmt.Sprintf("%v/%v:common:redis_sectigo_ov_%v_chain_pem.txt", RedisBaseURL, TeamName, CertNameUnderscored)
    		RedisFullChainURL = fmt.Sprintf("%v/%v:common:redis_sectigo_ov_%v_fullchain_pem.txt", RedisBaseURL, TeamName, CertNameUnderscored)
    	} else {
    		VaultURL = fmt.Sprintf("%v/%v/%v/vault_%v_key", VaultBaseURL, TeamName, CertName, CertNameUnderscored)
    		RedisCertURL = fmt.Sprintf("%v/%v:%v:redis_%v_pem.txt", RedisBaseURL, TeamName, CertName, CertNameUnderscored)
    		RedisCAURL = fmt.Sprintf("%v/%v:%v:redis_%v_chain_pem.txt", RedisBaseURL, TeamName, CertName, CertNameUnderscored)
    		RedisFullChainURL = fmt.Sprintf("%v/%v:%v:redis_%v_fullchain_pem.txt", RedisBaseURL, TeamName, CertName, CertNameUnderscored)
    	}
    
    	if arguments["--cert-destination"] == fmt.Sprintf(filepath.Join(CertBase, "<cert-name>.crt")) {
    		certificateDestination = fmt.Sprintf(filepath.Join(CertBase, fmt.Sprintf("%v.crt", CertName)))
    	} else {
    		certificateDestination = arguments["--cert-destination"].(string)
    	}
    	if arguments["--fullchain-destination"] == fmt.Sprintf(filepath.Join(CertBase, "<cert-name>_fullchain.crt")) {
    		fullchainDestination = fmt.Sprintf(filepath.Join(CertBase, fmt.Sprintf("%v_fullchain.crt", CertName)))
    	} else {
    		fullchainDestination = arguments["--fullchain-destination"].(string)
    	}
    	if arguments["--ca-destination"] == fmt.Sprintf(filepath.Join(CertBase, "COMODO_<type>.crt")) {
    		caDestination = fmt.Sprintf(filepath.Join(CertBase, fmt.Sprintf("COMODO_%v.crt", Type)))
    	} else {
    		caDestination = arguments["--ca-destination"].(string)
    	}
    	if arguments["--key-destination"] == fmt.Sprintf(filepath.Join(KeyBase, "<cert-name>.key")) {
    		keyDestination = fmt.Sprintf(filepath.Join(KeyBase, fmt.Sprintf("%v.key", CertName)))
    	} else {
    		keyDestination = arguments["--key-destination"].(string)
    	}
    
    	// check if there is a certificate installed and it is valid
    	existingCert := checkCertificates(CertName, certificateDestination, fullchainDestination, caDestination, keyDestination, Days, false)
    	existingKey := checkPrivkey(keyDestination, certificateDestination, false)
    	if existingCert == true && existingKey == true {
    		fmt.Printf("%v the certificate is still valid\n", infoMsg)
    		appExit(0)
    	}
    	certificate := GetRedisKey(RedisCertURL, RedisToken)
    	ca := GetRedisKey(RedisCAURL, RedisToken)
    	fullChain := GetRedisKey(RedisFullChainURL, RedisToken)
    	privKey := GetVaultKey(VaultURL, VaultToken)
    
    	// download and test certificates on a temporary location
    	WriteToFile(certificate, tmpCertificateDestination, 0644)
    	WriteToFile(fullChain, tmpFullchainDestination, 0644)
    	WriteToFile(ca, tmpCaDestination, 0644)
    	WriteToFile(privKey, tmpKeyDestination, 0640)
    
    	checkCertificates(CertName, tmpCertificateDestination, tmpFullchainDestination, tmpCaDestination, tmpKeyDestination, Days, true)
    	checkPrivkey(tmpKeyDestination, tmpCertificateDestination, true)
    
    	// move certificates in place
    	moveFile(tmpCertificateDestination, certificateDestination, GroupID, 0644, 0755)
    	moveFile(tmpFullchainDestination, fullchainDestination, GroupID, 0644, 0755)
    	moveFile(tmpCaDestination, caDestination, GroupID, 0644, 0755)
    	moveFile(tmpKeyDestination, keyDestination, GroupID, 0640, 0750)
    
    	// Exit 64: it means that the certificate was replaced and the
    	// application can be reloaded to make use of the new certificate
    	appExit(64)
    
    }