github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/topgun/core/credhub_test.go (about) 1 package topgun_test 2 3 import ( 4 "bufio" 5 "bytes" 6 "crypto/rand" 7 "crypto/rsa" 8 "crypto/x509" 9 "crypto/x509/pkix" 10 "encoding/json" 11 "encoding/pem" 12 "io/ioutil" 13 "math/big" 14 "os" 15 "path/filepath" 16 "strings" 17 "time" 18 19 "code.cloudfoundry.org/credhub-cli/credhub" 20 "code.cloudfoundry.org/credhub-cli/credhub/credentials/values" 21 "sigs.k8s.io/yaml" 22 23 . "github.com/pf-qiu/concourse/v6/topgun" 24 . "github.com/pf-qiu/concourse/v6/topgun/common" 25 . "github.com/onsi/ginkgo" 26 . "github.com/onsi/gomega" 27 ) 28 29 var _ = Describe("Credhub", func() { 30 BeforeEach(func() { 31 if !strings.Contains(string(Bosh("releases").Out.Contents()), "credhub") { 32 Skip("credhub release not uploaded") 33 } 34 }) 35 36 Describe("A deployment with credhub", func() { 37 var ( 38 credhubClient *credhub.CredHub 39 credhubInstance *BoshInstance 40 ) 41 42 BeforeEach(func() { 43 Deploy( 44 "deployments/concourse.yml", 45 "-o", "operations/add-empty-credhub.yml", 46 ) 47 48 credhubInstance = Instance("credhub") 49 postgresInstance := JobInstance("postgres") 50 51 varsDir, err := ioutil.TempDir("", "vars") 52 Expect(err).ToNot(HaveOccurred()) 53 54 defer os.RemoveAll(varsDir) 55 56 varsStore := filepath.Join(varsDir, "vars.yml") 57 err = generateCredhubCerts(varsStore) 58 Expect(err).ToNot(HaveOccurred()) 59 60 Deploy( 61 "deployments/concourse.yml", 62 "-o", "operations/add-credhub.yml", 63 "--vars-store", varsStore, 64 "-v", "credhub_ip="+credhubInstance.IP, 65 "-v", "postgres_ip="+postgresInstance.IP, 66 ) 67 68 varsBytes, err := ioutil.ReadFile(varsStore) 69 Expect(err).ToNot(HaveOccurred()) 70 71 var vars struct { 72 CredHubClient struct { 73 CA string `json:"ca"` 74 Certificate string `json:"certificate"` 75 PrivateKey string `json:"private_key"` 76 } `json:"credhub_client_topgun"` 77 } 78 79 err = yaml.Unmarshal(varsBytes, &vars) 80 Expect(err).ToNot(HaveOccurred()) 81 82 clientCert := filepath.Join(varsDir, "client.cert") 83 err = ioutil.WriteFile(clientCert, []byte(vars.CredHubClient.Certificate), 0644) 84 Expect(err).ToNot(HaveOccurred()) 85 86 clientKey := filepath.Join(varsDir, "client.key") 87 err = ioutil.WriteFile(clientKey, []byte(vars.CredHubClient.PrivateKey), 0644) 88 Expect(err).ToNot(HaveOccurred()) 89 90 credhubClient, err = credhub.New( 91 "https://"+credhubInstance.IP+":8844", 92 credhub.CaCerts(vars.CredHubClient.CA), 93 credhub.ClientCert(clientCert, clientKey), 94 ) 95 Expect(err).ToNot(HaveOccurred()) 96 }) 97 98 Describe("/api/v1/info/creds", func() { 99 type responseSkeleton struct { 100 CredHub struct { 101 URL string `json:"url"` 102 CACerts []string `json:"ca_certs"` 103 Health struct { 104 Error string `json:"error"` 105 Response struct { 106 Status string `json:"status"` 107 } `json:"response"` 108 Method string `json:"method"` 109 } `json:"health"` 110 PathPrefix string `json:"path_prefix"` 111 UAAClientID string `json:"uaa_client_id"` 112 } `json:"credhub"` 113 } 114 115 var ( 116 atcURL string 117 parsedResponse responseSkeleton 118 ) 119 120 BeforeEach(func() { 121 atcURL = "http://" + JobInstance("web").IP + ":8080" 122 }) 123 124 JustBeforeEach(func() { 125 token, err := FetchToken(atcURL, AtcUsername, AtcPassword) 126 Expect(err).ToNot(HaveOccurred()) 127 128 body, err := RequestCredsInfo(atcURL, token.AccessToken) 129 Expect(err).ToNot(HaveOccurred()) 130 131 err = json.Unmarshal(body, &parsedResponse) 132 Expect(err).ToNot(HaveOccurred()) 133 }) 134 135 It("contains credhub config", func() { 136 Expect(parsedResponse.CredHub.URL).To(Equal("https://" + credhubInstance.IP + ":8844")) 137 Expect(parsedResponse.CredHub.Health.Response).ToNot(BeNil()) 138 Expect(parsedResponse.CredHub.Health.Response.Status).To(Equal("UP")) 139 Expect(parsedResponse.CredHub.Health.Error).To(BeEmpty()) 140 }) 141 }) 142 143 testCredentialManagement(func() { 144 _, err := credhubClient.SetValue("/concourse/main/team_secret", values.Value("some_team_secret")) 145 Expect(err).ToNot(HaveOccurred()) 146 147 _, err = credhubClient.SetValue("/concourse/main/pipeline-creds-test/assertion_script", values.Value(assertionScript)) 148 Expect(err).ToNot(HaveOccurred()) 149 150 _, err = credhubClient.SetValue("/concourse/main/pipeline-creds-test/canary", values.Value("some_canary")) 151 Expect(err).ToNot(HaveOccurred()) 152 153 _, err = credhubClient.SetValue("/concourse/main/pipeline-creds-test/resource_type_secret", values.Value("some_resource_type_secret")) 154 Expect(err).ToNot(HaveOccurred()) 155 156 _, err = credhubClient.SetValue("/concourse/main/pipeline-creds-test/resource_secret", values.Value("some_resource_secret")) 157 Expect(err).ToNot(HaveOccurred()) 158 159 _, err = credhubClient.SetUser("/concourse/main/pipeline-creds-test/job_secret", values.User{ 160 Username: "some_username", 161 Password: "some_password", 162 }) 163 Expect(err).ToNot(HaveOccurred()) 164 165 _, err = credhubClient.SetValue("/concourse/main/pipeline-creds-test/resource_version", values.Value("some_exposed_version_secret")) 166 Expect(err).ToNot(HaveOccurred()) 167 }, func() { 168 _, err := credhubClient.SetValue("/concourse/main/team_secret", values.Value("some_team_secret")) 169 Expect(err).ToNot(HaveOccurred()) 170 171 _, err = credhubClient.SetValue("/concourse/main/resource_version", values.Value("some_exposed_version_secret")) 172 Expect(err).ToNot(HaveOccurred()) 173 }) 174 }) 175 }) 176 177 type Cert struct { 178 CA string `json:"ca"` 179 Certificate string `json:"certificate"` 180 PrivateKey string `json:"private_key"` 181 } 182 183 func generateCredhubCerts(filepath string) (err error) { 184 var vars struct { 185 CredHubCA Cert `json:"credhub_ca"` 186 CredHubClientAtc Cert `json:"credhub_client_atc"` 187 CredHubClientTopgun Cert `json:"credhub_client_topgun"` 188 } 189 190 key, _ := rsa.GenerateKey(rand.Reader, 2048) 191 192 // root ca cert 193 rootCaTemplate, rootCaCert, err := generateCert("credhubCA", "", true, x509.ExtKeyUsageServerAuth, nil, key) 194 if err != nil { 195 return err 196 } 197 198 var b bytes.Buffer 199 writer := bufio.NewWriter(&b) 200 201 pem.Encode(writer, &pem.Block{Type: "CERTIFICATE", Bytes: rootCaCert}) 202 writer.Flush() 203 rootCa := b.String() 204 b.Reset() 205 206 pem.Encode(writer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 207 writer.Flush() 208 rootCaKey := b.String() 209 b.Reset() 210 211 vars.CredHubCA.CA = rootCa 212 vars.CredHubCA.Certificate = rootCa 213 vars.CredHubCA.PrivateKey = rootCaKey 214 215 // client topgun cert 216 _, clientTopgunCert, err := generateCert("credhubCA", "app:eef9440f-7d2b-44b4-99e2-a619cbec99e6", false, x509.ExtKeyUsageClientAuth, &rootCaTemplate, key) 217 if err != nil { 218 return err 219 } 220 221 pem.Encode(writer, &pem.Block{Type: "CERTIFICATE", Bytes: clientTopgunCert}) 222 writer.Flush() 223 clientTopgun := b.String() 224 b.Reset() 225 226 vars.CredHubClientTopgun.CA = rootCa 227 vars.CredHubClientTopgun.Certificate = clientTopgun 228 vars.CredHubClientTopgun.PrivateKey = rootCaKey 229 230 // client atc cert 231 _, clientAtcCert, err := generateCert("concourse", "app:df4d7e2c-edfa-432d-ab7e-ee97846b06d0", false, x509.ExtKeyUsageClientAuth, &rootCaTemplate, key) 232 if err != nil { 233 return err 234 } 235 236 pem.Encode(writer, &pem.Block{Type: "CERTIFICATE", Bytes: clientAtcCert}) 237 writer.Flush() 238 clientAtc := b.String() 239 b.Reset() 240 241 vars.CredHubClientAtc.CA = rootCa 242 vars.CredHubClientAtc.Certificate = clientAtc 243 vars.CredHubClientAtc.PrivateKey = rootCaKey 244 245 varsYaml, _ := yaml.Marshal(&vars) 246 ioutil.WriteFile(filepath, varsYaml, 0644) 247 return nil 248 } 249 250 func generateCert(commonName string, orgUnit string, isCA bool, extKeyUsage x509.ExtKeyUsage, parent *x509.Certificate, priv *rsa.PrivateKey) (template x509.Certificate, cert []byte, err error) { 251 252 random := rand.Reader 253 now := time.Now() 254 then := now.Add(60 * 60 * 24 * 1000 * 1000 * 1000) // 24 hours 255 256 template = x509.Certificate{ 257 SerialNumber: big.NewInt(1), 258 Subject: pkix.Name{ 259 CommonName: commonName, 260 Organization: []string{"Cloud Foundry"}, 261 OrganizationalUnit: []string{orgUnit}, 262 }, 263 NotBefore: now, 264 NotAfter: then, 265 266 SubjectKeyId: []byte{1, 2, 3, 4}, 267 KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 268 ExtKeyUsage: []x509.ExtKeyUsage{extKeyUsage}, 269 270 BasicConstraintsValid: true, 271 IsCA: isCA, 272 } 273 274 if isCA { 275 parent = &template 276 } 277 278 cert, err = x509.CreateCertificate(random, &template, parent, &priv.PublicKey, priv) 279 280 return template, cert, err 281 }