Skip to content

Commit

Permalink
Chore!: Migrate tentacle certificate (#716)
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacCalligeros95 authored Aug 12, 2024
1 parent 44acc60 commit 5aec963
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 129 deletions.
2 changes: 1 addition & 1 deletion docs/resources/tentacle_certificate.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ resource "octopusdeploy_kubernetes_agent_deployment_target" "agent" {
### Read-Only

- `base64` (String, Sensitive) The base64 encoded pfx certificate.
- `id` (String) The ID of this resource.
- `id` (String) The unique ID for this resource.
- `thumbprint` (String) The SHA1 sum of the certificate represented in hexadecimal.


6 changes: 3 additions & 3 deletions octopusdeploy/random.go → internal/random.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package octopusdeploy
package internal

import (
"crypto/rand"
Expand All @@ -21,7 +21,7 @@ func generateRandomBytes(length int) []byte {
return randomBytes
}

func generateRandomCryptoString(length int) string {
func GenerateRandomCryptoString(length int) string {
result := make([]byte, length)
bufferSize := int(float64(length) * 1.3)
for i, j, randomBytes := 0, 0, []byte{}; i < length; j++ {
Expand All @@ -37,7 +37,7 @@ func generateRandomCryptoString(length int) string {
return string(result)
}

func generateRandomSerialNumber() big.Int {
func GenerateRandomSerialNumber() big.Int {
random := rand.Reader
randomSerialNumber, err := rand.Int(random, big.NewInt(9223372036854775807))
if err != nil {
Expand Down
1 change: 0 additions & 1 deletion octopusdeploy/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ func Provider() *schema.Provider {
"octopusdeploy_tag": resourceTag(),
"octopusdeploy_tag_set": resourceTagSet(),
"octopusdeploy_team": resourceTeam(),
"octopusdeploy_tentacle_certificate": resourceTentacleCertificate(),
"octopusdeploy_token_account": resourceTokenAccount(),
"octopusdeploy_user": resourceUser(),
"octopusdeploy_user_role": resourceUserRole(),
Expand Down
3 changes: 2 additions & 1 deletion octopusdeploy/resource_polling_subscription_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package octopusdeploy

import (
"context"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
Expand All @@ -27,7 +28,7 @@ func resourcePollingSubscriptionIdDelete(ctx context.Context, d *schema.Resource
}

func resourcePollingSubscriptionIdCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var generatedSubscriptionId = generateRandomCryptoString(20)
var generatedSubscriptionId = internal.GenerateRandomCryptoString(20)
d.SetId(generatedSubscriptionId)
d.Set("polling_uri", "poll://"+generatedSubscriptionId+"/")

Expand Down
97 changes: 0 additions & 97 deletions octopusdeploy/resource_tentacle_certificate.go

This file was deleted.

25 changes: 0 additions & 25 deletions octopusdeploy/schema_tentacle_certificate.go

This file was deleted.

1 change: 1 addition & 0 deletions octopusdeploy_framework/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewUsernamePasswordAccountResource,
NewRunbookResource,
NewTenantResource,
NewTentacleCertificateResource,
NewScriptModuleResource,
}
}
Expand Down
129 changes: 129 additions & 0 deletions octopusdeploy_framework/resource_tentacle_certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package octopusdeploy_framework

import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/hex"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal"
"software.sslmate.com/src/go-pkcs12"
"strings"
"time"

"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type tentacleCertificateResource struct {
*Config
}

func NewTentacleCertificateResource() resource.Resource {
return &tentacleCertificateResource{}
}

func (t *tentacleCertificateResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = util.GetTypeName("tentacle_certificate")
}

func (t *tentacleCertificateResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schemas.GetTentacleCertificateSchema()
}

func (t *tentacleCertificateResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
t.Config = ResourceConfiguration(req, resp)
}

func (t *tentacleCertificateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan schemas.TentacleCertificateResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

certificate, thumbprint, err := generateCertificate("Octopus Tentacle")

if err != nil {
resp.Diagnostics.AddError("cannot generate tentacle", err.Error())
return
}

plan.Base64 = types.StringValue(certificate)
plan.Thumbprint = types.StringValue(thumbprint)
plan.ID = types.StringValue(internal.GenerateRandomCryptoString(20))

resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)

}

func (t *tentacleCertificateResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
return
}

func (t *tentacleCertificateResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data schemas.TentacleCertificateResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

data.ID = types.StringValue("")
return
}

func (r *tentacleCertificateResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
return
}

func generateCertificate(fullName string) (string, string, error) {
random := rand.Reader

privateKey, err := rsa.GenerateKey(random, 2048)
if err != nil {
return "", "", err
}

serialNumber := internal.GenerateRandomSerialNumber()
template := x509.Certificate{
SerialNumber: &serialNumber,
Subject: pkix.Name{
CommonName: fullName,
},
Issuer: pkix.Name{
CommonName: fullName,
},
NotBefore: time.Now().AddDate(0, 0, -1),
NotAfter: time.Now().AddDate(100, 0, 0),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageServerAuth,
},
IsCA: false,
BasicConstraintsValid: true,
}

certBytes, err := x509.CreateCertificate(random, &template, &template, &privateKey.PublicKey, privateKey)
if err != nil {
return "", "", err
}

parsedCert, _ := x509.ParseCertificate(certBytes)
pkcs12Bytes, err := pkcs12.Passwordless.Encode(privateKey, parsedCert, nil, "")
if err != nil {
return "", "", err
}

pkcs12Base64 := base64.StdEncoding.EncodeToString(pkcs12Bytes)

thumbprint := sha1.Sum(certBytes)
thumbprintStr := strings.ToUpper(hex.EncodeToString(thumbprint[:]))

return pkcs12Base64, thumbprintStr, nil
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package octopusdeploy
package octopusdeploy_framework

import (
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
Expand Down
44 changes: 44 additions & 0 deletions octopusdeploy_framework/schemas/schema_tentacle_certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package schemas

import (
resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
)

func GetTentacleCertificateSchema() resourceSchema.Schema {
return resourceSchema.Schema{
Description: "Generates a X.509 self-signed certificate for use with a Octopus Deploy Tentacle.",
Attributes: map[string]resourceSchema.Attribute{
"id": resourceSchema.StringAttribute{
Description: "The unique ID for this resource.",
Computed: true,
},
"base64": resourceSchema.StringAttribute{
Computed: true,
Sensitive: true,
Description: "The base64 encoded pfx certificate.",
},
"thumbprint": resourceSchema.StringAttribute{
Computed: true,
Description: "The SHA1 sum of the certificate represented in hexadecimal.",
},
"dependencies": resourceSchema.MapAttribute{
Optional: true,
ElementType: types.StringType,
Description: "Optional map of dependencies that when modified will trigger a re-creation of this resource.",
PlanModifiers: []planmodifier.Map{
mapplanmodifier.RequiresReplace(),
},
},
},
}
}

type TentacleCertificateResourceModel struct {
ID types.String `tfsdk:"id"`
Base64 types.String `tfsdk:"base64"`
Thumbprint types.String `tfsdk:"thumbprint"`
Dependencies types.Map `tfsdk:"dependencies"`
}

0 comments on commit 5aec963

Please sign in to comment.