diff --git a/bin/gen-utils-fakes b/bin/gen-utils-fakes new file mode 100755 index 0000000..c2df782 --- /dev/null +++ b/bin/gen-utils-fakes @@ -0,0 +1,6 @@ +#!/bin/sh +set -e + +[ ! -d "vendor" ] && echo "$0 requires vendor/ folder, run 'go mod vendor'" + +counterfeiter -o pkg/credsgen/fakes/generator.go pkg/credsgen/ Generator \ No newline at end of file diff --git a/go.mod b/go.mod index 0d10899..4d4a23f 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,12 @@ module code.cloudfoundry.org/quarks-utils go 1.13 require ( - code.cloudfoundry.org/quarks-secret v1.0.692 + github.com/cloudflare/cfssl v1.4.1 + github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 github.com/go-logr/zapr v0.1.1 + github.com/google/go-cmp v0.3.1 // indirect + github.com/imdario/mergo v0.3.8 // indirect + github.com/json-iterator/go v1.1.9 // indirect github.com/onsi/ginkgo v1.11.0 github.com/onsi/gomega v1.8.1 github.com/pkg/errors v0.8.1 @@ -13,6 +17,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.1 go.uber.org/zap v1.13.0 + golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 gopkg.in/yaml.v2 v2.2.8 k8s.io/api v0.18.5 diff --git a/go.sum b/go.sum index d14255d..7246fd2 100644 --- a/go.sum +++ b/go.sum @@ -2,9 +2,6 @@ bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -code.cloudfoundry.org/quarks-secret v1.0.692 h1:TG1WROeiEhkR/h1FM3yiiehXF9jmmtzz+UGG4ehHfic= -code.cloudfoundry.org/quarks-secret v1.0.692/go.mod h1:Wbt2nVlC/EcKsZ6v6uxsARH47jadEO0flO+F9CeR7tY= -code.cloudfoundry.org/quarks-utils v0.0.0-20200630135315-de0c944c2813/go.mod h1:voPdeHf5x70u82CBFDCisvVFhxpXKuUEjd+b8y4Dcwo= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= @@ -44,6 +41,7 @@ github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEex github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= +github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw= github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= @@ -65,6 +63,7 @@ github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CL github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 h1:RAV05c0xOkJ3dZGS0JFybxFKZ2WMLabgx3uXnd7rpGs= github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -147,6 +146,7 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -166,6 +166,7 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -211,6 +212,7 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= +github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade h1:ryslCsfLTV4Cm/9NXqCJirlbYodWqFiTH454IaSn/fY= github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -225,6 +227,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49 h1:o/c0aWEP/m6n61xlYW2QP4t9424qlJOsxugn5Zds2Rg= github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -236,6 +239,7 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= +github.com/lib/pq v0.0.0-20180201184707-88edab080323 h1:Ou506ViB5uo2GloKFWIYi5hwRJn4AAOXuLVv8RMY9+4= github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -250,6 +254,7 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -336,7 +341,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -358,13 +362,16 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e h1:mvOa4+/DXStR4ZXOks/UsjeFdn5O5JpLUtzqk9U8xXw= github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= +github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg= github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -525,14 +532,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= k8s.io/api v0.18.5 h1:fKbCxr+U3fu7k6jB+QeYPD/c6xKYeSJ2KVWmyUypuWM= k8s.io/api v0.18.5/go.mod h1:tN+e/2nbdGKOAH55NMV8oGrMG+3uRlA9GaRfvnCCSNk= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= k8s.io/apiextensions-apiserver v0.18.5 h1:pvbXjB/BRXZiO+/Erp5Pxr+lnhDCv5uxNxHh3FLGZ/g= k8s.io/apiextensions-apiserver v0.18.5/go.mod h1:woZ7PkEIMHjhHIyApvOwkGOkBLUYKuet0VWVkPTQ/Fs= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.18.5 h1:Lh6tgsM9FMkC12K5T5QjRm7rDs6aQN5JHkA0JomULDM= k8s.io/apimachinery v0.18.5/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= diff --git a/pkg/credsgen/fakes/generator.go b/pkg/credsgen/fakes/generator.go new file mode 100644 index 0000000..74fec0b --- /dev/null +++ b/pkg/credsgen/fakes/generator.go @@ -0,0 +1,431 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package fakes + +import ( + "sync" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" +) + +type FakeGenerator struct { + GenerateCertificateStub func(string, credsgen.CertificateGenerationRequest) (credsgen.Certificate, error) + generateCertificateMutex sync.RWMutex + generateCertificateArgsForCall []struct { + arg1 string + arg2 credsgen.CertificateGenerationRequest + } + generateCertificateReturns struct { + result1 credsgen.Certificate + result2 error + } + generateCertificateReturnsOnCall map[int]struct { + result1 credsgen.Certificate + result2 error + } + GenerateCertificateSigningRequestStub func(credsgen.CertificateGenerationRequest) ([]byte, []byte, error) + generateCertificateSigningRequestMutex sync.RWMutex + generateCertificateSigningRequestArgsForCall []struct { + arg1 credsgen.CertificateGenerationRequest + } + generateCertificateSigningRequestReturns struct { + result1 []byte + result2 []byte + result3 error + } + generateCertificateSigningRequestReturnsOnCall map[int]struct { + result1 []byte + result2 []byte + result3 error + } + GeneratePasswordStub func(string, credsgen.PasswordGenerationRequest) string + generatePasswordMutex sync.RWMutex + generatePasswordArgsForCall []struct { + arg1 string + arg2 credsgen.PasswordGenerationRequest + } + generatePasswordReturns struct { + result1 string + } + generatePasswordReturnsOnCall map[int]struct { + result1 string + } + GenerateRSAKeyStub func(string) (credsgen.RSAKey, error) + generateRSAKeyMutex sync.RWMutex + generateRSAKeyArgsForCall []struct { + arg1 string + } + generateRSAKeyReturns struct { + result1 credsgen.RSAKey + result2 error + } + generateRSAKeyReturnsOnCall map[int]struct { + result1 credsgen.RSAKey + result2 error + } + GenerateSSHKeyStub func(string) (credsgen.SSHKey, error) + generateSSHKeyMutex sync.RWMutex + generateSSHKeyArgsForCall []struct { + arg1 string + } + generateSSHKeyReturns struct { + result1 credsgen.SSHKey + result2 error + } + generateSSHKeyReturnsOnCall map[int]struct { + result1 credsgen.SSHKey + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeGenerator) GenerateCertificate(arg1 string, arg2 credsgen.CertificateGenerationRequest) (credsgen.Certificate, error) { + fake.generateCertificateMutex.Lock() + ret, specificReturn := fake.generateCertificateReturnsOnCall[len(fake.generateCertificateArgsForCall)] + fake.generateCertificateArgsForCall = append(fake.generateCertificateArgsForCall, struct { + arg1 string + arg2 credsgen.CertificateGenerationRequest + }{arg1, arg2}) + fake.recordInvocation("GenerateCertificate", []interface{}{arg1, arg2}) + fake.generateCertificateMutex.Unlock() + if fake.GenerateCertificateStub != nil { + return fake.GenerateCertificateStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.generateCertificateReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeGenerator) GenerateCertificateCallCount() int { + fake.generateCertificateMutex.RLock() + defer fake.generateCertificateMutex.RUnlock() + return len(fake.generateCertificateArgsForCall) +} + +func (fake *FakeGenerator) GenerateCertificateCalls(stub func(string, credsgen.CertificateGenerationRequest) (credsgen.Certificate, error)) { + fake.generateCertificateMutex.Lock() + defer fake.generateCertificateMutex.Unlock() + fake.GenerateCertificateStub = stub +} + +func (fake *FakeGenerator) GenerateCertificateArgsForCall(i int) (string, credsgen.CertificateGenerationRequest) { + fake.generateCertificateMutex.RLock() + defer fake.generateCertificateMutex.RUnlock() + argsForCall := fake.generateCertificateArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeGenerator) GenerateCertificateReturns(result1 credsgen.Certificate, result2 error) { + fake.generateCertificateMutex.Lock() + defer fake.generateCertificateMutex.Unlock() + fake.GenerateCertificateStub = nil + fake.generateCertificateReturns = struct { + result1 credsgen.Certificate + result2 error + }{result1, result2} +} + +func (fake *FakeGenerator) GenerateCertificateReturnsOnCall(i int, result1 credsgen.Certificate, result2 error) { + fake.generateCertificateMutex.Lock() + defer fake.generateCertificateMutex.Unlock() + fake.GenerateCertificateStub = nil + if fake.generateCertificateReturnsOnCall == nil { + fake.generateCertificateReturnsOnCall = make(map[int]struct { + result1 credsgen.Certificate + result2 error + }) + } + fake.generateCertificateReturnsOnCall[i] = struct { + result1 credsgen.Certificate + result2 error + }{result1, result2} +} + +func (fake *FakeGenerator) GenerateCertificateSigningRequest(arg1 credsgen.CertificateGenerationRequest) ([]byte, []byte, error) { + fake.generateCertificateSigningRequestMutex.Lock() + ret, specificReturn := fake.generateCertificateSigningRequestReturnsOnCall[len(fake.generateCertificateSigningRequestArgsForCall)] + fake.generateCertificateSigningRequestArgsForCall = append(fake.generateCertificateSigningRequestArgsForCall, struct { + arg1 credsgen.CertificateGenerationRequest + }{arg1}) + fake.recordInvocation("GenerateCertificateSigningRequest", []interface{}{arg1}) + fake.generateCertificateSigningRequestMutex.Unlock() + if fake.GenerateCertificateSigningRequestStub != nil { + return fake.GenerateCertificateSigningRequestStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2, ret.result3 + } + fakeReturns := fake.generateCertificateSigningRequestReturns + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 +} + +func (fake *FakeGenerator) GenerateCertificateSigningRequestCallCount() int { + fake.generateCertificateSigningRequestMutex.RLock() + defer fake.generateCertificateSigningRequestMutex.RUnlock() + return len(fake.generateCertificateSigningRequestArgsForCall) +} + +func (fake *FakeGenerator) GenerateCertificateSigningRequestCalls(stub func(credsgen.CertificateGenerationRequest) ([]byte, []byte, error)) { + fake.generateCertificateSigningRequestMutex.Lock() + defer fake.generateCertificateSigningRequestMutex.Unlock() + fake.GenerateCertificateSigningRequestStub = stub +} + +func (fake *FakeGenerator) GenerateCertificateSigningRequestArgsForCall(i int) credsgen.CertificateGenerationRequest { + fake.generateCertificateSigningRequestMutex.RLock() + defer fake.generateCertificateSigningRequestMutex.RUnlock() + argsForCall := fake.generateCertificateSigningRequestArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeGenerator) GenerateCertificateSigningRequestReturns(result1 []byte, result2 []byte, result3 error) { + fake.generateCertificateSigningRequestMutex.Lock() + defer fake.generateCertificateSigningRequestMutex.Unlock() + fake.GenerateCertificateSigningRequestStub = nil + fake.generateCertificateSigningRequestReturns = struct { + result1 []byte + result2 []byte + result3 error + }{result1, result2, result3} +} + +func (fake *FakeGenerator) GenerateCertificateSigningRequestReturnsOnCall(i int, result1 []byte, result2 []byte, result3 error) { + fake.generateCertificateSigningRequestMutex.Lock() + defer fake.generateCertificateSigningRequestMutex.Unlock() + fake.GenerateCertificateSigningRequestStub = nil + if fake.generateCertificateSigningRequestReturnsOnCall == nil { + fake.generateCertificateSigningRequestReturnsOnCall = make(map[int]struct { + result1 []byte + result2 []byte + result3 error + }) + } + fake.generateCertificateSigningRequestReturnsOnCall[i] = struct { + result1 []byte + result2 []byte + result3 error + }{result1, result2, result3} +} + +func (fake *FakeGenerator) GeneratePassword(arg1 string, arg2 credsgen.PasswordGenerationRequest) string { + fake.generatePasswordMutex.Lock() + ret, specificReturn := fake.generatePasswordReturnsOnCall[len(fake.generatePasswordArgsForCall)] + fake.generatePasswordArgsForCall = append(fake.generatePasswordArgsForCall, struct { + arg1 string + arg2 credsgen.PasswordGenerationRequest + }{arg1, arg2}) + fake.recordInvocation("GeneratePassword", []interface{}{arg1, arg2}) + fake.generatePasswordMutex.Unlock() + if fake.GeneratePasswordStub != nil { + return fake.GeneratePasswordStub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + fakeReturns := fake.generatePasswordReturns + return fakeReturns.result1 +} + +func (fake *FakeGenerator) GeneratePasswordCallCount() int { + fake.generatePasswordMutex.RLock() + defer fake.generatePasswordMutex.RUnlock() + return len(fake.generatePasswordArgsForCall) +} + +func (fake *FakeGenerator) GeneratePasswordCalls(stub func(string, credsgen.PasswordGenerationRequest) string) { + fake.generatePasswordMutex.Lock() + defer fake.generatePasswordMutex.Unlock() + fake.GeneratePasswordStub = stub +} + +func (fake *FakeGenerator) GeneratePasswordArgsForCall(i int) (string, credsgen.PasswordGenerationRequest) { + fake.generatePasswordMutex.RLock() + defer fake.generatePasswordMutex.RUnlock() + argsForCall := fake.generatePasswordArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeGenerator) GeneratePasswordReturns(result1 string) { + fake.generatePasswordMutex.Lock() + defer fake.generatePasswordMutex.Unlock() + fake.GeneratePasswordStub = nil + fake.generatePasswordReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeGenerator) GeneratePasswordReturnsOnCall(i int, result1 string) { + fake.generatePasswordMutex.Lock() + defer fake.generatePasswordMutex.Unlock() + fake.GeneratePasswordStub = nil + if fake.generatePasswordReturnsOnCall == nil { + fake.generatePasswordReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.generatePasswordReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeGenerator) GenerateRSAKey(arg1 string) (credsgen.RSAKey, error) { + fake.generateRSAKeyMutex.Lock() + ret, specificReturn := fake.generateRSAKeyReturnsOnCall[len(fake.generateRSAKeyArgsForCall)] + fake.generateRSAKeyArgsForCall = append(fake.generateRSAKeyArgsForCall, struct { + arg1 string + }{arg1}) + fake.recordInvocation("GenerateRSAKey", []interface{}{arg1}) + fake.generateRSAKeyMutex.Unlock() + if fake.GenerateRSAKeyStub != nil { + return fake.GenerateRSAKeyStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.generateRSAKeyReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeGenerator) GenerateRSAKeyCallCount() int { + fake.generateRSAKeyMutex.RLock() + defer fake.generateRSAKeyMutex.RUnlock() + return len(fake.generateRSAKeyArgsForCall) +} + +func (fake *FakeGenerator) GenerateRSAKeyCalls(stub func(string) (credsgen.RSAKey, error)) { + fake.generateRSAKeyMutex.Lock() + defer fake.generateRSAKeyMutex.Unlock() + fake.GenerateRSAKeyStub = stub +} + +func (fake *FakeGenerator) GenerateRSAKeyArgsForCall(i int) string { + fake.generateRSAKeyMutex.RLock() + defer fake.generateRSAKeyMutex.RUnlock() + argsForCall := fake.generateRSAKeyArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeGenerator) GenerateRSAKeyReturns(result1 credsgen.RSAKey, result2 error) { + fake.generateRSAKeyMutex.Lock() + defer fake.generateRSAKeyMutex.Unlock() + fake.GenerateRSAKeyStub = nil + fake.generateRSAKeyReturns = struct { + result1 credsgen.RSAKey + result2 error + }{result1, result2} +} + +func (fake *FakeGenerator) GenerateRSAKeyReturnsOnCall(i int, result1 credsgen.RSAKey, result2 error) { + fake.generateRSAKeyMutex.Lock() + defer fake.generateRSAKeyMutex.Unlock() + fake.GenerateRSAKeyStub = nil + if fake.generateRSAKeyReturnsOnCall == nil { + fake.generateRSAKeyReturnsOnCall = make(map[int]struct { + result1 credsgen.RSAKey + result2 error + }) + } + fake.generateRSAKeyReturnsOnCall[i] = struct { + result1 credsgen.RSAKey + result2 error + }{result1, result2} +} + +func (fake *FakeGenerator) GenerateSSHKey(arg1 string) (credsgen.SSHKey, error) { + fake.generateSSHKeyMutex.Lock() + ret, specificReturn := fake.generateSSHKeyReturnsOnCall[len(fake.generateSSHKeyArgsForCall)] + fake.generateSSHKeyArgsForCall = append(fake.generateSSHKeyArgsForCall, struct { + arg1 string + }{arg1}) + fake.recordInvocation("GenerateSSHKey", []interface{}{arg1}) + fake.generateSSHKeyMutex.Unlock() + if fake.GenerateSSHKeyStub != nil { + return fake.GenerateSSHKeyStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.generateSSHKeyReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeGenerator) GenerateSSHKeyCallCount() int { + fake.generateSSHKeyMutex.RLock() + defer fake.generateSSHKeyMutex.RUnlock() + return len(fake.generateSSHKeyArgsForCall) +} + +func (fake *FakeGenerator) GenerateSSHKeyCalls(stub func(string) (credsgen.SSHKey, error)) { + fake.generateSSHKeyMutex.Lock() + defer fake.generateSSHKeyMutex.Unlock() + fake.GenerateSSHKeyStub = stub +} + +func (fake *FakeGenerator) GenerateSSHKeyArgsForCall(i int) string { + fake.generateSSHKeyMutex.RLock() + defer fake.generateSSHKeyMutex.RUnlock() + argsForCall := fake.generateSSHKeyArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeGenerator) GenerateSSHKeyReturns(result1 credsgen.SSHKey, result2 error) { + fake.generateSSHKeyMutex.Lock() + defer fake.generateSSHKeyMutex.Unlock() + fake.GenerateSSHKeyStub = nil + fake.generateSSHKeyReturns = struct { + result1 credsgen.SSHKey + result2 error + }{result1, result2} +} + +func (fake *FakeGenerator) GenerateSSHKeyReturnsOnCall(i int, result1 credsgen.SSHKey, result2 error) { + fake.generateSSHKeyMutex.Lock() + defer fake.generateSSHKeyMutex.Unlock() + fake.GenerateSSHKeyStub = nil + if fake.generateSSHKeyReturnsOnCall == nil { + fake.generateSSHKeyReturnsOnCall = make(map[int]struct { + result1 credsgen.SSHKey + result2 error + }) + } + fake.generateSSHKeyReturnsOnCall[i] = struct { + result1 credsgen.SSHKey + result2 error + }{result1, result2} +} + +func (fake *FakeGenerator) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.generateCertificateMutex.RLock() + defer fake.generateCertificateMutex.RUnlock() + fake.generateCertificateSigningRequestMutex.RLock() + defer fake.generateCertificateSigningRequestMutex.RUnlock() + fake.generatePasswordMutex.RLock() + defer fake.generatePasswordMutex.RUnlock() + fake.generateRSAKeyMutex.RLock() + defer fake.generateRSAKeyMutex.RUnlock() + fake.generateSSHKeyMutex.RLock() + defer fake.generateSSHKeyMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeGenerator) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ credsgen.Generator = new(FakeGenerator) diff --git a/pkg/credsgen/generator.go b/pkg/credsgen/generator.go new file mode 100644 index 0000000..3ae088f --- /dev/null +++ b/pkg/credsgen/generator.go @@ -0,0 +1,49 @@ +package credsgen + +const ( + // DefaultPasswordLength represents the default length of a generated password + // (number of characters) + DefaultPasswordLength = 64 +) + +// PasswordGenerationRequest specifies the generation parameters for Passwords +type PasswordGenerationRequest struct { + Length int +} + +// CertificateGenerationRequest specifies the generation parameters for Certificates +type CertificateGenerationRequest struct { + CommonName string + AlternativeNames []string + IsCA bool + CA Certificate +} + +// Certificate holds the information about a certificate +type Certificate struct { + IsCA bool + Certificate []byte + PrivateKey []byte +} + +// SSHKey represents an SSH key +type SSHKey struct { + PrivateKey []byte + PublicKey []byte + Fingerprint string +} + +// RSAKey represents an RSA key +type RSAKey struct { + PrivateKey []byte + PublicKey []byte +} + +// Generator provides an interface for generating credentials like passwords, certificates or SSH and RSA keys +type Generator interface { + GeneratePassword(name string, request PasswordGenerationRequest) string + GenerateCertificate(name string, request CertificateGenerationRequest) (Certificate, error) + GenerateCertificateSigningRequest(request CertificateGenerationRequest) ([]byte, []byte, error) + GenerateSSHKey(name string) (SSHKey, error) + GenerateRSAKey(name string) (RSAKey, error) +} diff --git a/pkg/credsgen/in_memory_generator/certificate.go b/pkg/credsgen/in_memory_generator/certificate.go new file mode 100644 index 0000000..45b8371 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/certificate.go @@ -0,0 +1,155 @@ +package inmemorygenerator + +import ( + "fmt" + "time" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + "github.com/cloudflare/cfssl/cli/genkey" + "github.com/cloudflare/cfssl/config" + "github.com/cloudflare/cfssl/csr" + "github.com/cloudflare/cfssl/helpers" + "github.com/cloudflare/cfssl/initca" + cfssllog "github.com/cloudflare/cfssl/log" + "github.com/cloudflare/cfssl/signer" + "github.com/cloudflare/cfssl/signer/local" + "github.com/pkg/errors" +) + +// GenerateCertificate generates a certificate using Cloudflare's TLS toolkit +func (g InMemoryGenerator) GenerateCertificate(name string, request credsgen.CertificateGenerationRequest) (credsgen.Certificate, error) { + g.log.Debugf("Generating certificate %s", name) + cfssllog.Level = cfssllog.LevelWarning + + var certificate credsgen.Certificate + var err error + + if request.IsCA { + certificate, err = g.generateCACertificate(request) + if err != nil { + return credsgen.Certificate{}, errors.Wrap(err, "Generating CA certificate failed.") + } + } else { + certificate, err = g.generateCertificate(request) + if err != nil { + return credsgen.Certificate{}, errors.Wrap(err, "Generating certificate failed.") + } + } + return certificate, nil +} + +// GenerateCertificateSigningRequest Generates a certificate signing request and private key +func (g InMemoryGenerator) GenerateCertificateSigningRequest(request credsgen.CertificateGenerationRequest) ([]byte, []byte, error) { + cfssllog.Level = cfssllog.LevelWarning + + var csReq, privateKey []byte + + // Generate certificate request + certReq := &csr.CertificateRequest{KeyRequest: &csr.KeyRequest{A: g.Algorithm, S: g.Bits}} + + certReq.Hosts = append(certReq.Hosts, request.CommonName) + certReq.Hosts = append(certReq.Hosts, request.AlternativeNames...) + certReq.CN = certReq.Hosts[0] + + sslValidator := &csr.Generator{Validator: genkey.Validator} + csReq, privateKey, err := sslValidator.ProcessRequest(certReq) + if err != nil { + return csReq, privateKey, err + } + return csReq, privateKey, nil +} + +// generateCertificate Generate a local-issued certificate and private key +func (g InMemoryGenerator) generateCertificate(request credsgen.CertificateGenerationRequest) (credsgen.Certificate, error) { + if !request.CA.IsCA { + return credsgen.Certificate{}, errors.Errorf("The passed CA is not a CA") + } + + cert := credsgen.Certificate{ + IsCA: false, + } + + // Generate certificate + signingReq, privateKey, err := g.GenerateCertificateSigningRequest(request) + if err != nil { + return credsgen.Certificate{}, err + } + // Sign certificate + signingProfile := &config.SigningProfile{ + Usage: []string{"server auth", "client auth"}, + Expiry: time.Duration(g.Expiry*24) * time.Hour, + ExpiryString: fmt.Sprintf("%dh", g.Expiry*24), + } + cert.Certificate, err = g.signCertificate(signingReq, signingProfile, request) + if err != nil { + return credsgen.Certificate{}, err + } + cert.PrivateKey = privateKey + + return cert, nil +} + +// generateCACertificate Generate self-signed root CA certificate and private key +func (g InMemoryGenerator) generateCACertificate(request credsgen.CertificateGenerationRequest) (credsgen.Certificate, error) { + req := &csr.CertificateRequest{ + CA: &csr.CAConfig{Expiry: fmt.Sprintf("%dh", g.Expiry*24)}, + CN: request.CommonName, + KeyRequest: &csr.KeyRequest{A: g.Algorithm, S: g.Bits}, + } + ca, csr, privateKey, err := initca.New(req) + if err != nil { + return credsgen.Certificate{}, err + } + + cert := credsgen.Certificate{ + IsCA: true, + Certificate: ca, + PrivateKey: privateKey, + } + if request.CA.IsCA { + signingProfile := &config.SigningProfile{ + Usage: []string{"cert sign", "crl sign"}, + ExpiryString: "43800h", + Expiry: 5 * helpers.OneYear, + CAConstraint: config.CAConstraint{ + IsCA: true, + }, + } + cert.Certificate, err = g.signCertificate(csr, signingProfile, request) + if err != nil { + return credsgen.Certificate{}, err + } + } + + return cert, nil +} + +// Given a signing profile, csr & request with CA, the certificate is signed by the CA. +func (g InMemoryGenerator) signCertificate(csr []byte, signingProfile *config.SigningProfile, request credsgen.CertificateGenerationRequest) ([]byte, error) { + + policy := &config.Signing{ + Profiles: map[string]*config.SigningProfile{}, + Default: signingProfile, + } + + // Parse parent CA + parentCACert, err := helpers.ParseCertificatePEM([]byte(request.CA.Certificate)) + if err != nil { + return []byte{}, errors.Wrap(err, "Parsing CA PEM failed.") + } + parentCAKey, err := helpers.ParsePrivateKeyPEM([]byte(request.CA.PrivateKey)) + if err != nil { + return []byte{}, errors.Wrap(err, "Parsing CA private key failed.") + } + + s, err := local.NewSigner(parentCAKey, parentCACert, signer.DefaultSigAlgo(parentCAKey), policy) + if err != nil { + return []byte{}, errors.Wrap(err, "Creating signer failed.") + } + certificate, err := s.Sign(signer.SignRequest{Request: string(csr)}) + if err != nil { + return []byte{}, errors.Wrap(err, "Signing certificate failed.") + } + + return certificate, nil +} diff --git a/pkg/credsgen/in_memory_generator/certificate_test.go b/pkg/credsgen/in_memory_generator/certificate_test.go new file mode 100644 index 0000000..b7c4b76 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/certificate_test.go @@ -0,0 +1,177 @@ +package inmemorygenerator_test + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + inmemorygenerator "code.cloudfoundry.org/quarks-utils/pkg/credsgen/in_memory_generator" + helper "code.cloudfoundry.org/quarks-utils/testing/testhelper" + + cfssllog "github.com/cloudflare/cfssl/log" + "github.com/pkg/errors" +) + +var _ = Describe("InMemoryGenerator", func() { + var ( + generator credsgen.Generator + ) + + BeforeEach(func() { + cfssllog.Level = cfssllog.LevelFatal + + _, log := helper.NewTestLogger() + generator = inmemorygenerator.NewInMemoryGenerator(log) + // speed up tests with a fast algo + g := generator.(*inmemorygenerator.InMemoryGenerator) + g.Algorithm = "ecdsa" + g.Bits = 256 + }) + + Describe("GenerateCertificate", func() { + Context("when generating a certificate", func() { + var ( + caCommonName string + request credsgen.CertificateGenerationRequest + ca credsgen.Certificate + ) + + BeforeEach(func() { + caCommonName = "Fake CA" + ca, _ = generator.GenerateCertificate("testca", credsgen.CertificateGenerationRequest{CommonName: caCommonName, IsCA: true}) + request = credsgen.CertificateGenerationRequest{ + IsCA: false, + CA: ca, + } + }) + + It("fails if the passed CA is not a CA", func() { + ca := credsgen.Certificate{ + IsCA: false, + } + + request.CA = ca + + _, err := generator.GenerateCertificate("foo", request) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("not a CA")) + }) + + It("considers the common name", func() { + request.CommonName = "foo.com" + cert, err := generator.GenerateCertificate("foo", request) + Expect(err).ToNot(HaveOccurred()) + + parsedCert, err := parseCert(cert.Certificate) + Expect(err).ToNot(HaveOccurred()) + + Expect(parsedCert.IsCA).To(BeFalse()) + Expect(parsedCert.DNSNames).To(ContainElement(Equal("foo.com"))) + Expect(parsedCert.Issuer.CommonName).To(Equal(caCommonName)) + }) + + It("considers the alternative names", func() { + request.CommonName = "foo.com" + request.AlternativeNames = []string{"bar.com", "baz.com"} + cert, err := generator.GenerateCertificate("foo", request) + Expect(err).ToNot(HaveOccurred()) + + parsedCert, err := parseCert(cert.Certificate) + Expect(err).ToNot(HaveOccurred()) + + Expect(parsedCert.IsCA).To(BeFalse()) + Expect(len(parsedCert.DNSNames)).To(Equal(3)) + Expect(parsedCert.DNSNames).To(ContainElement(Equal("bar.com"))) + Expect(parsedCert.DNSNames).To(ContainElement(Equal("baz.com"))) + }) + + Context("with custom parameters", func() { + It("considers all parameters", func() { + g := generator.(*inmemorygenerator.InMemoryGenerator) + g.Bits = 256 + g.Algorithm = "ecdsa" + g.Expiry = 1 + + cert, err := g.GenerateCertificate("foo", request) + Expect(err).ToNot(HaveOccurred()) + + key, _ := pem.Decode(cert.PrivateKey) + parsedCert, err := parseCert(cert.Certificate) + Expect(err).ToNot(HaveOccurred()) + + Expect(key.Type).To(Equal("EC PRIVATE KEY")) + Expect(parsedCert.NotAfter.Before(time.Now().AddDate(0, 0, 2))).To(BeTrue()) + Expect(len(cert.PrivateKey)).To(Equal(227)) + }) + }) + }) + + Context("when generating a CA", func() { + var ( + request credsgen.CertificateGenerationRequest + ) + + BeforeEach(func() { + request = credsgen.CertificateGenerationRequest{ + IsCA: true, + } + }) + + Context("creates a root CA", func() { + + var ( + cert credsgen.Certificate + err error + ) + + BeforeEach(func() { + request.CommonName = "example.com" + cert, err = generator.GenerateCertificate("foo", request) + Expect(err).ToNot(HaveOccurred()) + + parsedCert, err := parseCert(cert.Certificate) + Expect(err).ToNot(HaveOccurred()) + + Expect(parsedCert.IsCA).To(BeTrue()) + Expect(cert.PrivateKey).ToNot(BeEmpty()) + Expect(parsedCert.Subject.CommonName).To(Equal(request.CommonName)) + }) + + It("creates an intermediate CA", func() { + + request.CommonName = "exampleIntermediate.com" + request.CA = cert + cert, err = generator.GenerateCertificate("foo", request) + Expect(err).ToNot(HaveOccurred()) + + parsedCert, err := parseCert(cert.Certificate) + Expect(err).ToNot(HaveOccurred()) + + Expect(parsedCert.Issuer.CommonName).To(Equal("example.com")) + Expect(parsedCert.IsCA).To(BeTrue()) + Expect(cert.PrivateKey).ToNot(BeEmpty()) + Expect(parsedCert.Subject.CommonName).To(Equal(request.CommonName)) + }) + }) + }) + }) +}) + +func parseCert(certificate []byte) (*x509.Certificate, error) { + certBlob, _ := pem.Decode(certificate) + if certBlob == nil { + return nil, fmt.Errorf("could not decode certificate PEM") + } + + cert, err := x509.ParseCertificate(certBlob.Bytes) + if err != nil { + return nil, errors.Wrap(err, "parsing certificate") + } + + return cert, nil +} diff --git a/pkg/credsgen/in_memory_generator/in_memory_generator.go b/pkg/credsgen/in_memory_generator/in_memory_generator.go new file mode 100644 index 0000000..d733c81 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/in_memory_generator.go @@ -0,0 +1,20 @@ +package inmemorygenerator + +import ( + "go.uber.org/zap" +) + +// InMemoryGenerator represents a secret generator that generates everything +// by itself, using no 3rd party tools +type InMemoryGenerator struct { + Bits int // Key bits + Expiry int // Expiration (days) + Algorithm string // Algorithm type + + log *zap.SugaredLogger +} + +// NewInMemoryGenerator creates a default InMemoryGenerator +func NewInMemoryGenerator(log *zap.SugaredLogger) *InMemoryGenerator { + return &InMemoryGenerator{Bits: 2048, Expiry: 365, Algorithm: "rsa", log: log} +} diff --git a/pkg/credsgen/in_memory_generator/in_memory_generator_test.go b/pkg/credsgen/in_memory_generator/in_memory_generator_test.go new file mode 100644 index 0000000..6575300 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/in_memory_generator_test.go @@ -0,0 +1,43 @@ +package inmemorygenerator_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + inmemorygenerator "code.cloudfoundry.org/quarks-utils/pkg/credsgen/in_memory_generator" + helper "code.cloudfoundry.org/quarks-utils/testing/testhelper" +) + +var _ = Describe("InMemoryGenerator", func() { + var ( + defaultGenerator credsgen.Generator + ) + + BeforeEach(func() { + _, log := helper.NewTestLogger() + defaultGenerator = inmemorygenerator.NewInMemoryGenerator(log) + }) + + Describe("NewInMemoryGenerator", func() { + Context("object defaults", func() { + It("succeeds if the default type is inmemorygenerator.InMemoryGenerator", func() { + t, ok := defaultGenerator.(*inmemorygenerator.InMemoryGenerator) + Expect(ok).To(BeTrue()) + Expect(t).To(Equal(defaultGenerator)) + }) + + It("succeeds if the default generator is 2048 bits", func() { + Expect(defaultGenerator.(*inmemorygenerator.InMemoryGenerator).Bits).To(Equal(2048)) + }) + + It("succeeds if the default generator is rsa", func() { + Expect(defaultGenerator.(*inmemorygenerator.InMemoryGenerator).Algorithm).To(Equal("rsa")) + }) + + It("succeeds if the default generator certs expires in 365 days", func() { + Expect(defaultGenerator.(*inmemorygenerator.InMemoryGenerator).Expiry).To(Equal(365)) + }) + }) + }) +}) diff --git a/pkg/credsgen/in_memory_generator/password.go b/pkg/credsgen/in_memory_generator/password.go new file mode 100644 index 0000000..afd02cf --- /dev/null +++ b/pkg/credsgen/in_memory_generator/password.go @@ -0,0 +1,18 @@ +package inmemorygenerator + +import ( + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + "github.com/dchest/uniuri" +) + +// GeneratePassword generates a random password +func (g InMemoryGenerator) GeneratePassword(name string, request credsgen.PasswordGenerationRequest) string { + g.log.Debugf("Generating password %s", name) + + length := request.Length + if length == 0 { + length = credsgen.DefaultPasswordLength + } + + return uniuri.NewLen(length) +} diff --git a/pkg/credsgen/in_memory_generator/password_test.go b/pkg/credsgen/in_memory_generator/password_test.go new file mode 100644 index 0000000..385f40a --- /dev/null +++ b/pkg/credsgen/in_memory_generator/password_test.go @@ -0,0 +1,35 @@ +package inmemorygenerator_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + inmemorygenerator "code.cloudfoundry.org/quarks-utils/pkg/credsgen/in_memory_generator" + helper "code.cloudfoundry.org/quarks-utils/testing/testhelper" +) + +var _ = Describe("InMemoryGenerator", func() { + var ( + generator credsgen.Generator + ) + + BeforeEach(func() { + _, log := helper.NewTestLogger() + generator = inmemorygenerator.NewInMemoryGenerator(log) + }) + + Describe("GeneratePassword", func() { + It("has a default length", func() { + password := generator.GeneratePassword("foo", credsgen.PasswordGenerationRequest{}) + + Expect(len(password)).To(Equal(credsgen.DefaultPasswordLength)) + }) + + It("considers custom lengths", func() { + password := generator.GeneratePassword("foo", credsgen.PasswordGenerationRequest{Length: 10}) + + Expect(len(password)).To(Equal(10)) + }) + }) +}) diff --git a/pkg/credsgen/in_memory_generator/rsa_key.go b/pkg/credsgen/in_memory_generator/rsa_key.go new file mode 100644 index 0000000..60dc682 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/rsa_key.go @@ -0,0 +1,45 @@ +package inmemorygenerator + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + "github.com/pkg/errors" +) + +// GenerateRSAKey generates an RSA key using go's standard crypto library +func (g InMemoryGenerator) GenerateRSAKey(name string) (credsgen.RSAKey, error) { + g.log.Debugf("Generating RSA key %s", name) + + // generate private key + private, err := rsa.GenerateKey(rand.Reader, g.Bits) + if err != nil { + return credsgen.RSAKey{}, errors.Wrapf(err, "Generating private key failed for secret name %s", name) + } + privateBlock := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(private), + } + privatePEM := pem.EncodeToMemory(privateBlock) + + // Calculate public key + public := private.Public().(*rsa.PublicKey) + publicSerialized, err := x509.MarshalPKIXPublicKey(public) + if err != nil { + return credsgen.RSAKey{}, errors.Wrap(err, "generating public key") + } + publicBlock := &pem.Block{ + Type: "PUBLIC KEY", + Bytes: publicSerialized, + } + publicPEM := pem.EncodeToMemory(publicBlock) + + key := credsgen.RSAKey{ + PrivateKey: privatePEM, + PublicKey: publicPEM, + } + return key, nil +} diff --git a/pkg/credsgen/in_memory_generator/rsa_key_test.go b/pkg/credsgen/in_memory_generator/rsa_key_test.go new file mode 100644 index 0000000..145d475 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/rsa_key_test.go @@ -0,0 +1,31 @@ +package inmemorygenerator_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + inmemorygenerator "code.cloudfoundry.org/quarks-utils/pkg/credsgen/in_memory_generator" + helper "code.cloudfoundry.org/quarks-utils/testing/testhelper" +) + +var _ = Describe("InMemoryGenerator", func() { + var ( + generator credsgen.Generator + ) + + BeforeEach(func() { + _, log := helper.NewTestLogger() + generator = inmemorygenerator.NewInMemoryGenerator(log) + }) + + Describe("GenerateRSAKey", func() { + It("generates an RSA key", func() { + key, err := generator.GenerateRSAKey("foo") + + Expect(err).ToNot(HaveOccurred()) + Expect(key.PrivateKey).To(ContainSubstring("BEGIN RSA PRIVATE KEY")) + Expect(key.PublicKey).To(ContainSubstring("BEGIN PUBLIC KEY")) + }) + }) +}) diff --git a/pkg/credsgen/in_memory_generator/ssh_key.go b/pkg/credsgen/in_memory_generator/ssh_key.go new file mode 100644 index 0000000..e4cfbb1 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/ssh_key.go @@ -0,0 +1,41 @@ +package inmemorygenerator + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + "github.com/pkg/errors" + "golang.org/x/crypto/ssh" +) + +// GenerateSSHKey generates an SSH key using go's standard crypto library +func (g InMemoryGenerator) GenerateSSHKey(name string) (credsgen.SSHKey, error) { + g.log.Debugf("Generating SSH key %s", name) + + // generate private key + private, err := rsa.GenerateKey(rand.Reader, g.Bits) + if err != nil { + return credsgen.SSHKey{}, errors.Wrapf(err, "Generating ssh key failed for secret %s", name) + } + privateBlock := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(private), + } + privatePEM := pem.EncodeToMemory(privateBlock) + + // Calculate public key + public, err := ssh.NewPublicKey(&private.PublicKey) + if err != nil { + return credsgen.SSHKey{}, err + } + + key := credsgen.SSHKey{ + PrivateKey: privatePEM, + PublicKey: ssh.MarshalAuthorizedKey(public), + Fingerprint: ssh.FingerprintLegacyMD5(public), + } + return key, nil +} diff --git a/pkg/credsgen/in_memory_generator/ssh_key_test.go b/pkg/credsgen/in_memory_generator/ssh_key_test.go new file mode 100644 index 0000000..7ff88a8 --- /dev/null +++ b/pkg/credsgen/in_memory_generator/ssh_key_test.go @@ -0,0 +1,32 @@ +package inmemorygenerator_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" + inmemorygenerator "code.cloudfoundry.org/quarks-utils/pkg/credsgen/in_memory_generator" + helper "code.cloudfoundry.org/quarks-utils/testing/testhelper" +) + +var _ = Describe("InMemoryGenerator", func() { + var ( + generator credsgen.Generator + ) + + BeforeEach(func() { + _, log := helper.NewTestLogger() + generator = inmemorygenerator.NewInMemoryGenerator(log) + }) + + Describe("GenerateSSHKey", func() { + It("generates an SSH key", func() { + key, err := generator.GenerateSSHKey("foo") + + Expect(err).ToNot(HaveOccurred()) + Expect(key.PrivateKey).To(ContainSubstring("BEGIN RSA PRIVATE KEY")) + Expect(key.PublicKey).To(MatchRegexp("ssh-rsa\\s.+")) + Expect(key.Fingerprint).To(MatchRegexp("([0-9a-f]{2}:){15}[0-9a-f]{2}")) + }) + }) +}) diff --git a/pkg/credsgen/in_memory_generator/suite_test.go b/pkg/credsgen/in_memory_generator/suite_test.go new file mode 100644 index 0000000..7bd71ec --- /dev/null +++ b/pkg/credsgen/in_memory_generator/suite_test.go @@ -0,0 +1,13 @@ +package inmemorygenerator_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestInMemoryGenerator(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "InMemoryGenerator Suite") +} diff --git a/pkg/webhook/config.go b/pkg/webhook/config.go index 7103d56..356b62b 100644 --- a/pkg/webhook/config.go +++ b/pkg/webhook/config.go @@ -21,8 +21,8 @@ import ( machinerytypes "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - "code.cloudfoundry.org/quarks-secret/pkg/credsgen" "code.cloudfoundry.org/quarks-utils/pkg/config" + "code.cloudfoundry.org/quarks-utils/pkg/credsgen" "code.cloudfoundry.org/quarks-utils/pkg/ctxlog" )