| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- // +build ee
- package vault
- import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
- "time"
- "github.com/porter-dev/porter/internal/models/integrations"
- "github.com/porter-dev/porter/internal/repository/credentials"
- )
- // Client contains an API client for IronPlans
- type Client struct {
- apiKey string
- serverURL string
- secretPrefix string
- httpClient *http.Client
- }
- // NewClient creates a new billing API client
- func NewClient(serverURL, apiKey, secretPrefix string) *Client {
- httpClient := &http.Client{
- Timeout: time.Minute,
- }
- return &Client{apiKey, serverURL, secretPrefix, httpClient}
- }
- func (c *Client) WriteOAuthCredential(
- oauthIntegration *integrations.OAuthIntegration,
- data *credentials.OAuthCredential,
- ) error {
- reqData := &CreateVaultSecretRequest{
- Data: data,
- }
- return c.postRequest(fmt.Sprintf("/v1/%s", c.getOAuthCredentialPath(oauthIntegration)), reqData, nil)
- }
- func (c *Client) GetOAuthCredential(oauthIntegration *integrations.OAuthIntegration) (*credentials.OAuthCredential, error) {
- resp := &GetOAuthCredentialResponse{}
- err := c.getRequest(fmt.Sprintf("/v1/%s", c.getOAuthCredentialPath(oauthIntegration)), resp)
- if err != nil {
- return nil, err
- }
- return resp.Data.Data, nil
- }
- func (c *Client) CreateOAuthToken(oauthIntegration *integrations.OAuthIntegration) (string, error) {
- credPath := c.getOAuthCredentialPath(oauthIntegration)
- policyName := fmt.Sprintf("access-%d-oauth-%d", oauthIntegration.ProjectID, oauthIntegration.ID)
- return c.getToken(credPath, policyName)
- }
- func (c *Client) getOAuthCredentialPath(oauthIntegration *integrations.OAuthIntegration) string {
- return fmt.Sprintf(
- "kv/data/secret/%s/%d/oauth/%d",
- c.secretPrefix,
- oauthIntegration.ProjectID,
- oauthIntegration.ID,
- )
- }
- func (c *Client) WriteGCPCredential(
- gcpIntegration *integrations.GCPIntegration,
- data *credentials.GCPCredential) error {
- reqData := &CreateVaultSecretRequest{
- Data: data,
- }
- return c.postRequest(fmt.Sprintf("/v1/%s", c.getGCPCredentialPath(gcpIntegration)), reqData, nil)
- }
- func (c *Client) GetGCPCredential(gcpIntegration *integrations.GCPIntegration) (*credentials.GCPCredential, error) {
- resp := &GetGCPCredentialResponse{}
- err := c.getRequest(fmt.Sprintf("/v1/%s", c.getGCPCredentialPath(gcpIntegration)), resp)
- if err != nil {
- return nil, err
- }
- return resp.Data.Data, nil
- }
- func (c *Client) CreateGCPToken(gcpIntegration *integrations.GCPIntegration) (string, error) {
- credPath := c.getGCPCredentialPath(gcpIntegration)
- policyName := fmt.Sprintf("access-%d-gcp-%d", gcpIntegration.ProjectID, gcpIntegration.ID)
- return c.getToken(credPath, policyName)
- }
- func (c *Client) getGCPCredentialPath(gcpIntegration *integrations.GCPIntegration) string {
- return fmt.Sprintf(
- "kv/data/secret/%s/%d/gcp/%d",
- c.secretPrefix,
- gcpIntegration.ProjectID,
- gcpIntegration.ID,
- )
- }
- func (c *Client) WriteAWSCredential(
- awsIntegration *integrations.AWSIntegration,
- data *credentials.AWSCredential) error {
- reqData := &CreateVaultSecretRequest{
- Data: data,
- }
- return c.postRequest(fmt.Sprintf("/v1/%s", c.getAWSCredentialPath(awsIntegration)), reqData, nil)
- }
- func (c *Client) GetAWSCredential(awsIntegration *integrations.AWSIntegration) (*credentials.AWSCredential, error) {
- resp := &GetAWSCredentialResponse{}
- err := c.getRequest(fmt.Sprintf("/v1/%s", c.getAWSCredentialPath(awsIntegration)), resp)
- if err != nil {
- return nil, err
- }
- return resp.Data.Data, nil
- }
- func (c *Client) CreateAWSToken(awsIntegration *integrations.AWSIntegration) (string, error) {
- credPath := c.getAWSCredentialPath(awsIntegration)
- policyName := fmt.Sprintf("access-%d-aws-%d", awsIntegration.ProjectID, awsIntegration.ID)
- return c.getToken(credPath, policyName)
- }
- func (c *Client) getAWSCredentialPath(awsIntegration *integrations.AWSIntegration) string {
- return fmt.Sprintf(
- "kv/data/secret/%s/%d/aws/%d",
- c.secretPrefix,
- awsIntegration.ProjectID,
- awsIntegration.ID,
- )
- }
- func (c *Client) WriteAzureCredential(
- azIntegration *integrations.AzureIntegration,
- data *credentials.AzureCredential) error {
- reqData := &CreateVaultSecretRequest{
- Data: data,
- }
- return c.postRequest(fmt.Sprintf("/v1/%s", c.getAzureCredentialPath(azIntegration)), reqData, nil)
- }
- func (c *Client) GetAzureCredential(azIntegration *integrations.AzureIntegration) (*credentials.AzureCredential, error) {
- resp := &GetAzureCredentialResponse{}
- err := c.getRequest(fmt.Sprintf("/v1/%s", c.getAzureCredentialPath(azIntegration)), resp)
- if err != nil {
- return nil, err
- }
- return resp.Data.Data, nil
- }
- func (c *Client) CreateAzureToken(azIntegration *integrations.AzureIntegration) (string, error) {
- credPath := c.getAzureCredentialPath(azIntegration)
- policyName := fmt.Sprintf("access-%d-azure-%d", azIntegration.ProjectID, azIntegration.ID)
- return c.getToken(credPath, policyName)
- }
- func (c *Client) getAzureCredentialPath(azIntegration *integrations.AzureIntegration) string {
- return fmt.Sprintf(
- "kv/data/secret/%s/%d/azure/%d",
- c.secretPrefix,
- azIntegration.ProjectID,
- azIntegration.ID,
- )
- }
- const readOnlyPolicyTemplate = `path "%s" {
- capabilities = ["read"]
- }`
- func (c *Client) getToken(credPath, policyName string) (string, error) {
- policy := fmt.Sprintf(readOnlyPolicyTemplate, credPath)
- policyReq := &CreatePolicyRequest{
- Policy: policy,
- }
- err := c.postRequest(fmt.Sprintf("/v1/sys/policy/%s", policyName), policyReq, nil)
- if err != nil {
- return "", err
- }
- tokenReq := &CreateTokenRequest{
- Policies: []string{policyName},
- Meta: Meta{
- User: policyName,
- },
- TTL: "6h",
- }
- tokenResp := &CreateTokenResponse{}
- err = c.postRequest("/v1/auth/token/create", tokenReq, tokenResp)
- if err != nil {
- return "", err
- }
- return tokenResp.Auth.Token, nil
- }
- func (c *Client) postRequest(path string, data interface{}, dst interface{}) error {
- return c.writeRequest("POST", path, data, dst)
- }
- func (c *Client) putRequest(path string, data interface{}, dst interface{}) error {
- return c.writeRequest("PUT", path, data, dst)
- }
- func (c *Client) deleteRequest(path string, data interface{}, dst interface{}) error {
- return c.writeRequest("DELETE", path, data, dst)
- }
- func (c *Client) getRequest(path string, dst interface{}) error {
- reqURL, err := url.Parse(c.serverURL)
- if err != nil {
- return nil
- }
- reqURL.Path = path
- req, err := http.NewRequest(
- "GET",
- reqURL.String(),
- nil,
- )
- if err != nil {
- return err
- }
- req.Header.Set("Content-Type", "application/json; charset=utf-8")
- req.Header.Set("Accept", "application/json; charset=utf-8")
- req.Header.Set("X-Vault-Token", c.apiKey)
- res, err := c.httpClient.Do(req)
- if err != nil {
- return err
- }
- defer res.Body.Close()
- if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
- resBytes, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("request failed with status code %d, but could not read body (%s)\n", res.StatusCode, err.Error())
- }
- return fmt.Errorf("request failed with status code %d: %s\n", res.StatusCode, string(resBytes))
- }
- if dst != nil {
- return json.NewDecoder(res.Body).Decode(dst)
- }
- return nil
- }
- func (c *Client) writeRequest(method, path string, data interface{}, dst interface{}) error {
- reqURL, err := url.Parse(c.serverURL)
- if err != nil {
- return nil
- }
- reqURL.Path = path
- var strData []byte
- if data != nil {
- strData, err = json.Marshal(data)
- if err != nil {
- return err
- }
- }
- req, err := http.NewRequest(
- method,
- reqURL.String(),
- strings.NewReader(string(strData)),
- )
- if err != nil {
- return err
- }
- req.Header.Set("Content-Type", "application/json; charset=utf-8")
- req.Header.Set("Accept", "application/json; charset=utf-8")
- req.Header.Set("X-Vault-Token", c.apiKey)
- res, err := c.httpClient.Do(req)
- if err != nil {
- return err
- }
- defer res.Body.Close()
- if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
- resBytes, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("request failed with status code %d, but could not read body (%s)\n", res.StatusCode, err.Error())
- }
- return fmt.Errorf("request failed with status code %d: %s\n", res.StatusCode, string(resBytes))
- }
- if dst != nil {
- return json.NewDecoder(res.Body).Decode(dst)
- }
- return nil
- }
|