> ## Documentation Index
> Fetch the complete documentation index at: https://docs.endorlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Endor Outpost

> Deploy on-premises scanning within your Kubernetes cluster for air-gapped environments.

export const Diagram = ({children}) => {
  const [svg, setSvg] = useState('');
  const [error, setError] = useState(null);
  const [mounted, setMounted] = useState(false);
  const [id] = useState(() => `diagram-${Math.random().toString(36).slice(2)}`);
  const DEFAULTS = {
    theme: 'base',
    fontSize: '14px',
    fontFamily: 'inherit',
    primaryColor: '#26D07C',
    primaryTextColor: '#000000',
    primaryBorderColor: '#059669',
    secondaryColor: '#e5e7eb',
    secondaryTextColor: '#000000',
    secondaryBorderColor: '#9ca3af',
    tertiaryColor: '#e5e7eb',
    tertiaryTextColor: '#000000',
    tertiaryBorderColor: '#9ca3af',
    lineColor: '#6b7280',
    background: '#ffffff',
    edgeLabelBackground: '#f9fafb',
    clusterBkg: '#f0fdf4',
    clusterBorder: '#059669',
    nodeTextColor: '#000000',
    endorColor: '#26D07C',
    endorBorder: '#059669',
    managedColor: '#A7F3D0',
    managedBorder: '#059669',
    externalColor: '#e5e7eb',
    externalBorder: '#9ca3af'
  };
  const VAR_LINE_RE = /^(\w+):\s*(.+)$/;
  const TOKEN_RE = /\{\{(\w+)\}\}/g;
  const parseVarsBlock = raw => {
    const vars = {};
    const lines = raw.trim().split('\n');
    const diagramLines = [];
    let inVars = false;
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed === '%%vars') {
        inVars = true;
        continue;
      }
      if (inVars && trimmed === '%%') {
        inVars = false;
        continue;
      }
      if (inVars) {
        const m = VAR_LINE_RE.exec(trimmed);
        if (m) vars[m[1]] = m[2];
      } else {
        diagramLines.push(line);
      }
    }
    return {
      vars,
      diagramLines
    };
  };
  const buildInitConfig = merged => ({
    theme: merged.theme,
    themeVariables: {
      fontSize: merged.fontSize,
      fontFamily: merged.fontFamily,
      primaryColor: merged.primaryColor,
      primaryTextColor: merged.primaryTextColor,
      primaryBorderColor: merged.primaryBorderColor,
      secondaryColor: merged.secondaryColor,
      secondaryTextColor: merged.secondaryTextColor,
      secondaryBorderColor: merged.secondaryBorderColor,
      tertiaryColor: merged.tertiaryColor,
      tertiaryTextColor: merged.tertiaryTextColor,
      tertiaryBorderColor: merged.tertiaryBorderColor,
      lineColor: merged.lineColor,
      background: merged.background,
      edgeLabelBackground: merged.edgeLabelBackground,
      clusterBkg: merged.clusterBkg,
      clusterBorder: merged.clusterBorder,
      nodeTextColor: merged.nodeTextColor
    }
  });
  const renderWithMermaid = (mermaid, fullDiagram) => {
    mermaid.initialize({
      startOnLoad: false,
      zoom: {
        enabled: false
      }
    });
    mermaid.render(id, fullDiagram).then(({svg: rendered}) => {
      setSvg(rendered);
      setError(null);
    }).catch(err => setError(err.message));
  };
  useEffect(() => {
    setMounted(true);
  }, []);
  useEffect(() => {
    if (!mounted || !children) return;
    const raw = typeof children === 'string' ? children : String(children);
    const {vars, diagramLines} = parseVarsBlock(raw);
    const merged = {
      ...DEFAULTS,
      ...vars
    };
    const diagram = diagramLines.join('\n').trim().replaceAll(TOKEN_RE, (_, key) => merged[key] || '');
    const fullDiagram = `%%{init: ${JSON.stringify(buildInitConfig(merged))}}%%\n${diagram}`;
    const existing = document.getElementById(id);
    if (existing) existing.remove();
    if (globalThis.mermaid) {
      renderWithMermaid(globalThis.mermaid, fullDiagram);
    } else {
      const script = document.createElement('script');
      script.src = 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js';
      script.onload = () => renderWithMermaid(globalThis.mermaid, fullDiagram);
      script.onerror = () => setError('Failed to load Mermaid');
      document.head.appendChild(script);
    }
  }, [mounted, children, id]);
  if (!mounted) return null;
  if (error) {
    return <pre style={{
      color: '#dc2626',
      background: '#fef2f2',
      padding: '12px',
      borderRadius: '6px',
      fontSize: '13px',
      overflowX: 'auto'
    }}>
        Diagram error: {error}
      </pre>;
  }
  if (!svg) {
    return <div style={{
      height: '200px',
      background: '#f3f4f6',
      borderRadius: '8px',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      color: '#9ca3af',
      fontSize: '14px'
    }}>
        Loading diagram...
      </div>;
  }
  return <div dangerouslySetInnerHTML={{
    __html: svg
  }} style={{
    overflowX: 'auto',
    padding: '8px 0'
  }} />;
};

Endor Labs monitoring scan regularly scans your source code to discover vulnerabilities. The Endor Labs Apps clone and analyze all repositories every 24 hours, ensuring continuous monitoring for open source vulnerabilities and code weaknesses. See [Monitoring scans](/setup-deployment/scm-integrations) for more information.

Endor Labs uses a Kubernetes cluster where your source code repositories and cloned, and the scans are conducted. Your policies may require that the source code repositories are not exposed to the public cloud. In such situations, you can use Outpost, which is a deployable on-prem instance of the Endor Labs scheduler that runs on your private Kubernetes cluster. After you deploy Outpost, Endor Labs uses your Kubernetes cluster to run the monitoring scans.

The scheduling of the scans and the scans themselves are run within your firewall. After the scans are completed, only the scan results are sent to Endor Labs.

Outpost provides full feature parity with regular cloud-based Endor Labs scans.

The following diagram shows how monitoring scans work when you configure Outpost.

<Diagram>
  {`
    graph TD
      A(["Endor Labs App"]) -->|Continuous monitoring| B["Source Code Repositories"]
      B <--> F["Private Artifact Registry"]
      A -->|Initiates scans| C["Private Kubernetes cluster
      <span style='font-size: 12px'>Runs Outpost and the scans inside your firewall</span>"]
      B -->|Clones repositories| C
      C -->|Pass scan data| D(["Endor Labs Platform
      <span style='font-size: 12px'>Generate findings from scan results</span>"])

      subgraph E["Firewall"]
      A
      B
      C
      F
      end

      class A,D endor
      class B,C,F customer
      class E firewall
      classDef customer fill:#5EEAD4
      classDef firewall fill:transparent,stroke-dasharray: 5 5,stroke:#FF4500,color:#FF4500
    `}
</Diagram>

Outpost helps you in the following instances:

* Security and compliance requirements prevent you from exposing source code repositories to external services
* Firewall restrictions that prevent direct integration with external scan services and requires complex VPN configurations
* Integrating endorctl into multiple CI/CD pipelines can be complex and costly, and relying on manual scanning processes increases the risk of errors
* Need to scan against private artifact registries and internal services

You need to configure Outpost as an integration at your Endor Labs tenant namespace. You can only configure Outpost as an integration at your root namespace. After you configure the integration and complete the Kubernetes cluster configuration, all the monitoring scans in your Endor Labs tenant are run on your Kubernetes cluster.

<Warning>
  After configuring Outpost, you cannot use the cloud-based Endor Labs scheduler. You cannot choose to run scans of a particular project on the cloud-based Endor Labs scheduler and others with Outpost. All monitoring scans in your Endor Labs tenant will be carried out on your Kubernetes cluster.
</Warning>

The following sections describe how you can configure and deploy Outpost.

* [Outpost requirements](/setup-deployment/outpost/outpost-requirements)
* [Outpost authentication](/setup-deployment/outpost/outpost-authentication)
* [Outpost configuration](/setup-deployment/outpost/outpost-configuration)
