1import"../chunks/Bzak7iHL.js";import"../chunks/Cu8yTRT6.js";import{x as n,a1 as $,b6 as i,a6 as c,K as T,a_ as a,$ as x,aA as s,aL as S}from"../chunks/tHWzkC21.js";import{h as E}from"../chunks/ClIHA1yg.js";import{C as A}from"../chunks/DSiGV02n.js";import{H as _}from"../chunks/CkwJwLyB.js";import{C as r}from"../chunks/DR00_3tq.js";import{I as C}from"../chunks/C68Ma9LA.js";var q=c('<meta name="description" content="Use your build server to build your first application"/>'),B=c('An endpoint that has a security context enabled requires the following: <ul><li>For personal agents & actions the user must be the owner to trigger the action in the workspace (play button).</li> <li>For personal agents & actions the user must still use a bearer token to trigger the action or agent outside of the dashboard.</li> <li>For organizational / teams the user must have the <em class="text-highlight">Resource Protected</em> permission to trigger the endpoint from the dashboard.</li> <li>For organizational / teams the endpoint must be triggered with the valid bearer token. Please safe guard your private secret key used to generate bearer tokens.</li></ul>',1),P=c(`<div class="box"><!> <!> <h2>Introduction</h2> <p>Bruce is a lightweight build server designed for efficient iteration and seamless integration with your workflows. In this tutorial, we'll explore the concepts of enabling just-in-time access to your systems and applications.</p> <h2>Requirements & Getting Started</h2> <p>Setting up at least a basic Bruce installation, or following the Build Server guides, will provide a foundation for understanding the concepts in this guide. For reference, visit the <a href="/guides/build-server-1">Build 2 Server, Part 1</a> guide. Key points that we will focus on include the ability to make use of the Bruce workspace actions to trigger specific events that enable just in time access to your systems.</p> <h2>Theory and architecture behind this problem</h2> <p>Just in time access implies the ability to grant access to a system or application when it is needed, and to revoke that access when it is no longer required. This is a common problem in many organizations, where access to systems is 3 granted for a specific purpose, but the access is not revoked after the task is completed. This can lead to security vulnerabilities and potential data breaches. Bruce provides a solution to this problem by enabling you to create events 4 that can trigger a door opening from the inside of your network, allowing access to a system or application for a specific period of time. This access can be revoked automatically after the task is completed, ensuring that your systems 5 remain secure. The notion of opening the door from the inside ensures you have a guard internal that can open the door which is something that is extremely hard to do with traditional systems. Letâs dive into how Bruce can help solve this 6 problem.</p> <p>To reduce the complexity of the problem, we will focus on a simple use case of fully disabling ssh on a linux instance, and only enabling it when access is required, then shortly afterwards disabling it again ensuring that the access is 7 removed once a time window has passed.</p> <h2>Lets build it</h2> <p>To get started, we first need to create a new agent and action on the system. We can borrow from the build server guides to bootstrap the beginning of this process. The first step is to create a systemd unit file that 8 starts the agent on boot and ensures that it is always running. This is a simple process that can be done by creating a new file in <em class="text-highlight">/etc/systemd/system/bruce-agent.service</em> with the following contents:</p> <!> <p>As with before the unit file starts bruce in server mode and points to a local file (can be remote also, for the root configuration). An example of this base configuration looks like below:</p> <!> <p>Some key items to review here which is slightly different from previous guides include the use of the scp:// protocol to pull the agent configuration from a remote server. This is a powerful feature of Bruce that allows you to centralize 9 your agent configurations and ensure that they are always up to date. This allows you to dynamically adapt the agent configuration for your systems as time goes on. As of this writing the configuration can be read from a local 10 file, s3, scp, http or https locations, giving a massive amount of flexibility not only in how you configure your agents but also in how you manage and maintain them.</p> <p>The new action that was created include a custom actions called <em class="text-highlight">jit-ssh-on</em> and <em class="text-highlight">jit-ssh-off</em> which will be used to enable and disable ssh on the system. So lets take a look at 11 what these manifests may look like below.</p> <h2>Keeping it Simple</h2> <p>For illustration purposes we will keep this very short and simple, for simplicity sake we'll assume bruce is running as root here. The first manifest enables
11SSH on the system, and the second disables it:</p> <p>/etc/bruce/just-in-time-ssh-on.yml:</p> <!> <p>/etc/bruce/just-in-time-ssh-off.yml:</p> <!> <h2>Letâs Review</h2> <p>While this is an extremely simple example, in reality you may want to set SELinux contexts, update the firewall or updating additional things, the key takeaway here is that even in this simple example we can ensure that SSH is only enabled 12 when it is needed and disabled when it is not. This capability ensures your systems are secure by granting access only when required and revoking it once it's no longer needed.</p> <h2>Make It Actionable</h2> <p>The final part of this guide is to make it actionable from outside of the system. Something sends our man on the inside a message to open the door. This is done in the bruce.tools workspace. As before we create 2 new actions in the 13 workspace that map to the <em class="text-highlight">jit-ssh-on</em> and <em class="text-highlight">jit-ssh-off</em> actions. Once these are created you can trigger them by clicking the play button in the workspace. You can also trigger 14 them via their respective endpoints, be sure to enable a security key for these actions to ensure that only authorized users and systems can trigger them.</p> <p>For brevity the process of creating the actions is not shown here, but it is the same as in the build server guides. The key takeaway is that you can create custom actions to enable and disable SSH on your systems, triggered securely from 15 external sources within your control.</p> <h2>Endpoint Security</h2> <!> <p>To ensure that these capabilities do not get misused you should consider adding a security context to your actions and agents. This ensures that you make use of a secure token that will be able to trigger the endpoint and no other means 16 will be allowed, preventing a regular person from doing a curl command to gain access to your box without the appropriate entitlements or access.</p> <p>Once you apply a Security Context (Checkbox when creating & editing your action) you will be presented by a Secret Key input box that you can either use the generate button to generate a key or use your own provided key. The key will be 17 used in order to generate the bearer token that will be evaluated on the server side. Examples of how to create a sha-256 bearer token is below:</p> <p>Bash</p> <!> <p>Golang</p> <!> <p>Python</p> <!> <p>JavaScript</p> <!> <h2>Conclusion</h2> <p>In this guide we have looked at how to enable just in time access to your systems and applications using Bruce. By creating custom actions that can be triggered from the outside, you can ensure that access is only granted when it is 18 needed and that it is revoked when it is no longer required. This is a powerful capability that can be used to ensure that your systems are secure and that access is only granted when it is needed. Additionally, this capability can extend to 19 running automated playbooks and other tasks, eliminating the need for manual system access. Weâll explore this further in an upcoming NOC/SOC runbook guide.</p></div>`);function G(v){var l=P();E("rfctiu",e=>{var o=q();$(()=>{x.title="Bruce - Just-in-Time Access"}),n(e,o)});var h=T(l);A(h,{alignment:"center",image:"/pictures/digital-corridor.jpg",title:"Just in time Access",subTitle:"Access when you need it!"});var u=a(h,2);_(u,{title:"Just in time access",type:"h2"});var d=a(u,20);r(d,{language:"yaml",children:(e,o)=>{s();var t=i(`[Unit] 20Description=Bruce Build Server 21After=docker.service 22Requires=docker.service 23 24[Service] 25User=bruce 26Group=bruce 27TimeoutStartSec=5 28Restart=always 29ExecStart=/usr/local/bin/bruce server /etc/bruce/node.yml 30 31[Install] 32WantedBy=multi-user.target`);n(e,t)},$$slots:{default:!0}});var p=a(d,4);r(p,{language:"yaml",children:(e,o)=>{s();var t=i(`--- 33endpoint: <Agent Endpoint> 34runner-id: <Agent ID> 35authorization: <Auth Key> 36execution: 37- name: node action 38 action: default 39 type: event 40 target: scp://secure-access-server.yourdomain.com/$(hostname -f)/agent.yml 41- name: just in time ssh 42 action: jit-ssh-on 43 type: event 44 target: /etc/bruce/just-in-time-ssh-on.yml 45- name: just in time ssh off 46 action: jit-ssh-off 47 type: event 48 target: /etc/bruce/just-in-time-ssh-off.yml`);n(e,t)},$$slots:{default:!0}});var m=a(p,12);r(m,{language:"yaml",children:(e,o)=>{s();var t=i(`--- 49steps: 50- cmd: /usr/bin/systemctl start sshd`);n(e,t)},$$slots:{default:!0}});var y=a(m,4);r(y,{language:"yaml",children:(e,o)=>{s();var t=i(`--- 51steps: 52- cmd: /usr/bin/systemctl stop sshd`);n(e,t)},$$slots:{default:!0}});var g=a(y,14);C(g,{type:"info",children:(e,o)=>{s();var t=B();s(),n(e,t)},$$slots:{default:!0}});var f=a(g,8);r(f,{language:"bash",children:(e,o)=>{s();var t=i(`#!/bin/bash 53# Variables 54ENDPOINT="https://bruce.tools/your-endpoint" 55SECURITY_KEY="your-security-key" 56TIMESTAMP=$(date +%s) 57 58# Create payload and token 59PAYLOAD="\${\\"key\\":\\"$SECURITY_KEY\\",\\"iat\\":$TIMESTAMP}" 60TOKEN=$(echo -n $PAYLOAD | openssl dgst -sha256 -hmac $SECURITY_KEY | awk '\${print $2}') 61 62# Make the GET request 63curl -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" $ENDPOINT`);n(e,t)},$$slots:{default:!0}});var b=a(f,4);r(b,{language:"go",children:(e,o)=>{s();var t=i(`package main 64 65import ( 66 "crypto/hmac" 67 "crypto/sha256" 68 "encoding/hex" 69 "fmt" 70 "net/http" 71 "time" 72) 73 74func main() \${ 75 endpoint := "https://bruce.tools/your-endpoint" 76 securityKey := "your-security-key" 77 78 // Generate Bearer Token 79 timestamp := time.Now().Unix() 80 payload := fmt.Sprintf(\`\${"key":"%s","iat":%d}\`, securityKey, timestamp) 81 token := generateHMACSHA256(payload, securityKey) 82 83 // Make GET request 84 client := &http.Client\${} 85 req, err := http.NewRequest("GET", endpoint, nil) 86 if err != nil \${ 87 fmt.Println("Error creating request:", err) 88 return 89 } 90 req.Header.Set("Authorization", "Bearer "+token) 91 req.Header.Set("Content-Type", "application/json") 92 93 resp, err := client.Do(req) 94 if err != nil \${ 95 fmt.Println("Error making request:", err) 96 return 97 } 98 defer resp.Body.Close() 99 100 fmt.Println("Response Status:", resp.Status) 101} 102 103// Function to create an HMAC-SHA256 signature 104func generateHMACSHA256(payload, key string) string \${ 105 h := hmac.New(sha256.New, []byte(key)) 106 h.Write([]byte(payload)) 107 return hex.EncodeToString(h.Sum(nil)) 108}`);n(e,t)},$$slots:{default:!0}});var w=a(b,4);r(w,{language:"python",children:(e,o)=>{s();var t=i(`import hashlib 109import hmac 110import time 111import requests 112 113# Variables 114ENDPOINT = "https://bruce.tools/your-endpoint" 115SECURITY_KEY = "your-security-key" 116 117# Generate Bearer Token 118timestamp = int(time.time()) 119payload = f'{{"key":"{SECURITY_KEY}","iat":{timestamp}}}' 120token = hmac.new(SECURITY_KEY.encode(), payload.encode(), hashlib.sha256).hexdigest() 121 122# Make GET request 123headers = { 124 "Authorization": f"Bearer {token}", 125 "Content-Type": "application/json" 126} 127response = requests.get(ENDPOINT, headers=headers) 128 129print("Response Status:", response.status_code) 130print("Response Body:", response.text)`);n(e,t)},$$slots:{default:!0}});var k=a(w,4);r(k,{language:"javascript",children:(e,o)=>{s();var t=i(`const crypto = require("crypto"); 131const https = require("https"); 132 133// Variables 134const endpoint = "https://bruce.tools/your-endpoint"; 135const securityKey = "your-security-key"; 136 137// Generate Bearer Token 138const timestamp = Math.floor(Date.now() / 1000); 139const payload = \`{"key":"\${securityKey}","iat":\${timestamp}}\`; 140const token = crypto.createHmac("sha256", securityKey).update(payload).digest("hex"); 141 142// Make GET request 143const options = { 144 hostname: "bruce.tools", 145 path: "/your-endpoint", 146 method: "GET", 147 headers: { 148 "Authorization": \`Bearer \${token}\`, 149 "Content-Type": "application/json" 150 } 151}; 152 153const req = https.request(options, (res) => { 154 console.log(\`Status Code: \${res.statusCode}\`); 155 res.on("data", (data) => { 156 process.stdout.write(data); 157 }); 158}); 159 160req.on("error", (e) => { 161 console.error(\`Error: \${e.message}\`); 162}); 163 164req.end();`);n(e,t)},$$slots:{default:!0}}),s(4),S(l),n(v,l)}export{G as component};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.