mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-30 23:34:27 +00:00
feat(azure): add Deploy-to-Azure Bicep template and certificate auth
This commit is contained in:
1 parent
ab738e8a4e
commit
d2df95546b
9 files changed
+712
-18
No files matched your search
+83
-3
@@ -1,14 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { Control } from "react-hook-form";
|
||||
import { useState } from "react";
|
||||
import { Control, useFormContext } from "react-hook-form";
|
||||
|
||||
import {
|
||||
WizardInputField,
|
||||
WizardTextareaField,
|
||||
} from "@/components/providers/workflow/forms/fields";
|
||||
import { Button } from "@/components/shadcn";
|
||||
import {
|
||||
downloadPublicCertificateFile,
|
||||
generateProwlerCertificate,
|
||||
} from "@/lib/azure-cert-generator";
|
||||
import { getAzureDeploymentQuickLink } from "@/lib/external-urls";
|
||||
import { ProviderCredentialFields } from "@/lib/provider-credentials/provider-credential-fields";
|
||||
import { AzureCertificateCredentials } from "@/types";
|
||||
|
||||
export const AzureCertificateCredentialsForm = ({
|
||||
@@ -23,6 +29,45 @@ export const AzureCertificateCredentialsForm = ({
|
||||
// or region, thread that value through `getAzureDeploymentQuickLink` here.
|
||||
const deployToAzureUrl = getAzureDeploymentQuickLink();
|
||||
|
||||
// Feedback state for the in-browser certificate generator. Kept local
|
||||
// because the values only matter to this component — nothing else in the
|
||||
// wizard needs to know that the user opted for auto-generation.
|
||||
const [isGeneratingCert, setIsGeneratingCert] = useState(false);
|
||||
const [generatorError, setGeneratorError] = useState<string | null>(null);
|
||||
const [generatedThumbprint, setGeneratedThumbprint] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
const { setValue } = useFormContext<AzureCertificateCredentials>();
|
||||
|
||||
const handleGenerateCertificate = async () => {
|
||||
setGeneratorError(null);
|
||||
setGeneratedThumbprint(null);
|
||||
setIsGeneratingCert(true);
|
||||
try {
|
||||
const result = await generateProwlerCertificate();
|
||||
// Auto-fill the private key textarea with the ready-to-paste bundle so
|
||||
// the user does not need to touch the field manually. `shouldValidate`
|
||||
// clears the "Certificate Private Key is required" error immediately.
|
||||
setValue(
|
||||
ProviderCredentialFields.CERTIFICATE_CONTENT,
|
||||
result.privateKeyBundleBase64Pem,
|
||||
{ shouldValidate: true, shouldDirty: true, shouldTouch: true },
|
||||
);
|
||||
// Hand the public certificate to the user as a file: they upload it to
|
||||
// the Bicep `Certificate Base64` parameter in the Azure Portal.
|
||||
downloadPublicCertificateFile(result.publicCertificateBase64Der);
|
||||
setGeneratedThumbprint(result.thumbprintHex);
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to generate the certificate in-browser. Fall back to the openssl or PowerShell instructions in the guide.";
|
||||
setGeneratorError(message);
|
||||
} finally {
|
||||
setIsGeneratingCert(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
@@ -48,6 +93,40 @@ export const AzureCertificateCredentialsForm = ({
|
||||
“Certificate Private Key” field below.
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-content-neutral-tertiary flex flex-col items-start gap-2 rounded-md border border-dashed p-3">
|
||||
<div className="text-text-neutral-primary text-sm font-semibold">
|
||||
Don't have a certificate yet?
|
||||
</div>
|
||||
<p className="text-text-neutral-tertiary text-xs">
|
||||
Generate a self-signed X.509 certificate right in your browser. The
|
||||
<strong> private key never leaves your device</strong> — it goes
|
||||
straight into the field below. The public certificate downloads as a
|
||||
text file for you to paste into the Bicep{" "}
|
||||
<code>Certificate Base64</code> parameter in the Portal.
|
||||
</p>
|
||||
<Button
|
||||
type="button"
|
||||
variant="default"
|
||||
size="sm"
|
||||
onClick={handleGenerateCertificate}
|
||||
disabled={isGeneratingCert}
|
||||
>
|
||||
{isGeneratingCert
|
||||
? "Generating…"
|
||||
: "Generate certificate for me"}
|
||||
</Button>
|
||||
{generatorError && (
|
||||
<p className="text-text-error-primary text-xs">{generatorError}</p>
|
||||
)}
|
||||
{generatedThumbprint && (
|
||||
<p className="text-text-success-primary text-xs">
|
||||
Done. Certificate SHA-1 thumbprint: <code>{generatedThumbprint}</code>
|
||||
. Downloaded <code>prowler-cert-base64.txt</code> — paste its
|
||||
contents into the Bicep <code>Certificate Base64</code> parameter,
|
||||
then keep filling the fields below.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<WizardInputField
|
||||
control={control}
|
||||
name="tenant_id"
|
||||
@@ -81,8 +160,9 @@ export const AzureCertificateCredentialsForm = ({
|
||||
<p className="text-text-neutral-tertiary text-sm">
|
||||
This is the <strong>base64-encoded private key</strong> that matches the
|
||||
certificate uploaded to Entra ID by the Bicep template (not the public
|
||||
certificate, and not the thumbprint). Generation instructions (openssl /
|
||||
PowerShell) are in the{" "}
|
||||
certificate, and not the thumbprint). Use the{" "}
|
||||
<em>Generate certificate for me</em> button above, or follow the manual
|
||||
openssl / PowerShell instructions in the{" "}
|
||||
<Link
|
||||
href="https://docs.prowler.com/user-guide/providers/azure/authentication#certificate-authentication"
|
||||
target="_blank"
|
||||
|
||||
Reference in new issue
Block a user