cluster.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. package models
  2. import (
  3. "encoding/json"
  4. "github.com/porter-dev/porter/internal/models/integrations"
  5. "gorm.io/gorm"
  6. )
  7. // ClusterAuth is an auth mechanism that a cluster candidate can resolve
  8. type ClusterAuth string
  9. // The support cluster candidate auth mechanisms
  10. const (
  11. X509 ClusterAuth = "x509"
  12. Basic = "basic"
  13. Bearer = "bearerToken"
  14. OIDC = "oidc"
  15. GCP = "gcp-sa"
  16. AWS = "aws-sa"
  17. Local = "local"
  18. )
  19. // Cluster is an integration that can connect to a Kubernetes cluster via
  20. // a specific auth mechanism
  21. type Cluster struct {
  22. gorm.Model
  23. // The auth mechanism that this cluster will use
  24. AuthMechanism ClusterAuth `json:"auth_mechanism"`
  25. // The project that this integration belongs to
  26. ProjectID uint `json:"project_id"`
  27. // Name of the cluster
  28. Name string `json:"name"`
  29. // Server endpoint for the cluster
  30. Server string `json:"server"`
  31. // Additional fields optionally used by the kube client
  32. ClusterLocationOfOrigin string `json:"location_of_origin,omitempty"`
  33. TLSServerName string `json:"tls-server-name,omitempty"`
  34. InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"`
  35. ProxyURL string `json:"proxy-url,omitempty"`
  36. UserLocationOfOrigin string
  37. UserImpersonate string `json:"act-as,omitempty"`
  38. UserImpersonateGroups string `json:"act-as-groups,omitempty"`
  39. // ------------------------------------------------------------------
  40. // All fields below this line are encrypted before storage
  41. // ------------------------------------------------------------------
  42. // The various auth mechanisms available to the integration
  43. KubeIntegrationID uint
  44. OIDCIntegrationID uint
  45. GCPIntegrationID uint
  46. AWSIntegrationID uint
  47. // A token cache that can be used by an auth mechanism, if desired
  48. TokenCache integrations.TokenCache `json:"token_cache"`
  49. // CertificateAuthorityData for the cluster, encrypted at rest
  50. CertificateAuthorityData []byte `json:"certificate-authority-data,omitempty"`
  51. }
  52. // ClusterExternal is an external Cluster to be shared over REST
  53. type ClusterExternal struct {
  54. ID uint `json:"id"`
  55. // The project that this integration belongs to
  56. ProjectID uint `json:"project_id"`
  57. // Name of the cluster
  58. Name string `json:"name"`
  59. // Server endpoint for the cluster
  60. Server string `json:"server"`
  61. }
  62. // Externalize generates an external Cluster to be shared over REST
  63. func (c *Cluster) Externalize() *ClusterExternal {
  64. return &ClusterExternal{
  65. ID: c.ID,
  66. ProjectID: c.ProjectID,
  67. Name: c.Name,
  68. Server: c.Server,
  69. }
  70. }
  71. // ClusterCandidate is a cluster integration that requires additional action
  72. // from the user to set up.
  73. type ClusterCandidate struct {
  74. gorm.Model
  75. // The auth mechanism that this candidate will parse for
  76. AuthMechanism ClusterAuth `json:"auth_mechanism"`
  77. // The project that this integration belongs to
  78. ProjectID uint `json:"project_id"`
  79. // CreatedClusterID is the ID of the cluster that's eventually
  80. // created
  81. CreatedClusterID uint `json:"created_cluster_id"`
  82. // Resolvers are the list of resolvers: once all resolvers are "resolved," the
  83. // cluster will be created
  84. Resolvers []ClusterResolver `json:"resolvers"`
  85. // Name of the cluster
  86. Name string `json:"name"`
  87. // Server endpoint for the cluster
  88. Server string `json:"server"`
  89. // Name of the context that this was created from, if it exists
  90. ContextName string `json:"context_name"`
  91. // ------------------------------------------------------------------
  92. // All fields below this line are encrypted before storage
  93. // ------------------------------------------------------------------
  94. // The best-guess for the AWSClusterID, which is required by aws auth mechanisms
  95. // See https://github.com/kubernetes-sigs/aws-iam-authenticator#what-is-a-cluster-id
  96. AWSClusterIDGuess []byte `json:"aws_cluster_id_guess"`
  97. // The raw kubeconfig
  98. Kubeconfig []byte `json:"kubeconfig"`
  99. }
  100. // ClusterCandidateExternal represents the ClusterCandidate to be sent over REST
  101. type ClusterCandidateExternal struct {
  102. ID uint `json:"id"`
  103. // The project that this integration belongs to
  104. ProjectID uint `json:"project_id"`
  105. // CreatedClusterID is the ID of the cluster that's eventually
  106. // created
  107. CreatedClusterID uint `json:"created_cluster_id"`
  108. // Name of the cluster
  109. Name string `json:"name"`
  110. // Server endpoint for the cluster
  111. Server string `json:"server"`
  112. // Name of the context that this was created from, if it exists
  113. ContextName string `json:"context_name"`
  114. // Resolvers are the list of resolvers: once all resolvers are "resolved," the
  115. // cluster will be created
  116. Resolvers []ClusterResolverExternal `json:"resolvers"`
  117. // The best-guess for the AWSClusterID, which is required by aws auth mechanisms
  118. // See https://github.com/kubernetes-sigs/aws-iam-authenticator#what-is-a-cluster-id
  119. AWSClusterIDGuess string `json:"aws_cluster_id_guess"`
  120. }
  121. // Externalize generates an external ClusterCandidateExternal to be shared over REST
  122. func (cc *ClusterCandidate) Externalize() *ClusterCandidateExternal {
  123. resolvers := make([]ClusterResolverExternal, 0)
  124. for _, resolver := range cc.Resolvers {
  125. resolvers = append(resolvers, *resolver.Externalize())
  126. }
  127. return &ClusterCandidateExternal{
  128. ID: cc.ID,
  129. ProjectID: cc.ProjectID,
  130. CreatedClusterID: cc.CreatedClusterID,
  131. Name: cc.Name,
  132. Server: cc.Server,
  133. ContextName: cc.ContextName,
  134. Resolvers: resolvers,
  135. AWSClusterIDGuess: string(cc.AWSClusterIDGuess),
  136. }
  137. }
  138. // ClusterResolverName is the name for a cluster resolve
  139. type ClusterResolverName string
  140. // Options for the cluster resolver names
  141. const (
  142. ClusterCAData ClusterResolverName = "upload-cluster-ca-data"
  143. ClusterLocalhost = "rewrite-cluster-localhost"
  144. ClientCertData = "upload-client-cert-data"
  145. ClientKeyData = "upload-client-key-data"
  146. OIDCIssuerData = "upload-oidc-idp-issuer-ca-data"
  147. TokenData = "upload-token-data"
  148. GCPKeyData = "upload-gcp-key-data"
  149. AWSData = "upload-aws-data"
  150. )
  151. // ClusterResolverInfo contains the information for actions to be
  152. // performed in order to initialize a cluster
  153. type ClusterResolverInfo struct {
  154. // Docs is a link to documentation that helps resolve this manually
  155. Docs string `json:"docs"`
  156. // a comma-separated list of required fields to send in an action request
  157. Fields string `json:"fields"`
  158. }
  159. // ClusterResolverInfos is a map of the information for actions to be
  160. // performed in order to initialize a cluster
  161. var ClusterResolverInfos = map[ClusterResolverName]ClusterResolverInfo{
  162. ClusterCAData: ClusterResolverInfo{
  163. Docs: "https://github.com/porter-dev/porter",
  164. Fields: "cluster_ca_data",
  165. },
  166. ClusterLocalhost: ClusterResolverInfo{
  167. Docs: "https://github.com/porter-dev/porter",
  168. Fields: "cluster_hostname",
  169. },
  170. ClientCertData: ClusterResolverInfo{
  171. Docs: "https://github.com/porter-dev/porter",
  172. Fields: "client_cert_data",
  173. },
  174. ClientKeyData: ClusterResolverInfo{
  175. Docs: "https://github.com/porter-dev/porter",
  176. Fields: "client_key_data",
  177. },
  178. OIDCIssuerData: ClusterResolverInfo{
  179. Docs: "https://github.com/porter-dev/porter",
  180. Fields: "oidc_idp_issuer_ca_data",
  181. },
  182. TokenData: ClusterResolverInfo{
  183. Docs: "https://github.com/porter-dev/porter",
  184. Fields: "token_data",
  185. },
  186. GCPKeyData: ClusterResolverInfo{
  187. Docs: "https://github.com/porter-dev/porter",
  188. Fields: "gcp_key_data",
  189. },
  190. AWSData: ClusterResolverInfo{
  191. Docs: "https://github.com/porter-dev/porter",
  192. Fields: "aws_access_key_id,aws_secret_access_key,aws_cluster_id",
  193. },
  194. }
  195. // ClusterResolverAll is a helper type that contains the fields for
  196. // all possible resolvers, so that raw bytes can be unmarshaled in a single
  197. // read
  198. type ClusterResolverAll struct {
  199. ClusterCAData string `json:"cluster_ca_data,omitempty"`
  200. ClusterHostname string `json:"cluster_hostname,omitempty"`
  201. ClientCertData string `json:"client_cert_data,omitempty"`
  202. ClientKeyData string `json:"client_key_data,omitempty"`
  203. OIDCIssuerCAData string `json:"oidc_idp_issuer_ca_data,omitempty"`
  204. TokenData string `json:"token_data,omitempty"`
  205. GCPKeyData string `json:"gcp_key_data,omitempty"`
  206. AWSAccessKeyID string `json:"aws_access_key_id"`
  207. AWSSecretAccessKey string `json:"aws_secret_access_key"`
  208. AWSClusterID string `json:"aws_cluster_id"`
  209. }
  210. // ClusterResolver is an action that must be resolved to set up
  211. // a Cluster
  212. type ClusterResolver struct {
  213. gorm.Model
  214. // The ClusterCandidate that this is resolving
  215. ClusterCandidateID uint `json:"cluster_candidate_id"`
  216. // One of the ClusterResolverNames
  217. Name ClusterResolverName `json:"name"`
  218. // Resolved is true if this has been resolved, false otherwise
  219. Resolved bool `json:"resolved"`
  220. // Data is additional data for resolving the action, for example a file name,
  221. // context name, etc
  222. Data []byte `json:"data,omitempty"`
  223. }
  224. // ClusterResolverData is a map of key names to fields, which gets marshaled from
  225. // the raw JSON bytes stored in the ClusterResolver
  226. type ClusterResolverData map[string]string
  227. // ClusterResolverExternal is an external ClusterResolver to be shared over REST
  228. type ClusterResolverExternal struct {
  229. ID uint `json:"id"`
  230. // The ClusterCandidate that this is resolving
  231. ClusterCandidateID uint `json:"cluster_candidate_id"`
  232. // One of the ClusterResolverNames
  233. Name ClusterResolverName `json:"name"`
  234. // Resolved is true if this has been resolved, false otherwise
  235. Resolved bool `json:"resolved"`
  236. // Docs is a link to documentation that helps resolve this manually
  237. Docs string `json:"docs"`
  238. // Fields is a list of fields that must be sent with the resolving request
  239. Fields string `json:"fields"`
  240. // Data is additional data for resolving the action, for example a file name,
  241. // context name, etc
  242. Data ClusterResolverData `json:"data,omitempty"`
  243. }
  244. // Externalize generates an external ClusterResolver to be shared over REST
  245. func (cr *ClusterResolver) Externalize() *ClusterResolverExternal {
  246. info := ClusterResolverInfos[cr.Name]
  247. data := make(ClusterResolverData)
  248. json.Unmarshal(cr.Data, &data)
  249. return &ClusterResolverExternal{
  250. ID: cr.ID,
  251. ClusterCandidateID: cr.ClusterCandidateID,
  252. Name: cr.Name,
  253. Resolved: cr.Resolved,
  254. Docs: info.Docs,
  255. Fields: info.Fields,
  256. Data: data,
  257. }
  258. }