Added interactive AWS key setup/scoutsuite configuration

This commit is contained in:
VakarisZ 2020-10-01 15:02:54 +03:00
parent 708d1a697d
commit dd3d5d317a
21 changed files with 474 additions and 43 deletions

View File

@ -24,3 +24,7 @@ class AlreadyRegisteredError(RegistrationNotNeededError):
class RulePathCreatorNotFound(Exception): class RulePathCreatorNotFound(Exception):
""" Raise to indicate that ScoutSuite rule doesn't have a path creator""" """ Raise to indicate that ScoutSuite rule doesn't have a path creator"""
class InvalidAWSKeys(Exception):
""" Raise to indicate that AWS API keys are invalid"""

View File

@ -47,6 +47,8 @@ from monkey_island.cc.resources.test.monkey_test import MonkeyTest
from monkey_island.cc.resources.version_update import VersionUpdate from monkey_island.cc.resources.version_update import VersionUpdate
from monkey_island.cc.resources.zero_trust.finding_event import \ from monkey_island.cc.resources.zero_trust.finding_event import \
ZeroTrustFindingEvent ZeroTrustFindingEvent
from monkey_island.cc.resources.zero_trust.scoutsuite_auth.aws_keys import AWSKeys
from monkey_island.cc.resources.zero_trust.scoutsuite_auth.scoutsuite_auth import ScoutSuiteAuth
from monkey_island.cc.services.database import Database from monkey_island.cc.services.database import Database
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
from monkey_island.cc.services.representations import output_json from monkey_island.cc.services.representations import output_json
@ -146,6 +148,8 @@ def init_api_resources(api):
api.add_resource(VersionUpdate, '/api/version-update', '/api/version-update/') api.add_resource(VersionUpdate, '/api/version-update', '/api/version-update/')
api.add_resource(RemotePortCheck, '/api/monkey_control/check_remote_port/<string:port>') api.add_resource(RemotePortCheck, '/api/monkey_control/check_remote_port/<string:port>')
api.add_resource(StartedOnIsland, '/api/monkey_control/started_on_island') api.add_resource(StartedOnIsland, '/api/monkey_control/started_on_island')
api.add_resource(ScoutSuiteAuth, '/api/scoutsuite_auth/<string:provider>')
api.add_resource(AWSKeys, '/api/aws_keys')
api.add_resource(MonkeyTest, '/api/test/monkey') api.add_resource(MonkeyTest, '/api/test/monkey')
api.add_resource(ClearCaches, '/api/test/clear_caches') api.add_resource(ClearCaches, '/api/test/clear_caches')

View File

@ -0,0 +1,11 @@
import flask_restful
from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import get_aws_keys
class AWSKeys(flask_restful.Resource):
@jwt_required
def get(self):
return get_aws_keys()

View File

@ -0,0 +1,34 @@
import json
import flask_restful
from flask import request
from common.cloud.scoutsuite_consts import PROVIDERS
from common.utils.exceptions import InvalidAWSKeys
from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import is_cloud_authentication_setup, \
set_aws_keys
class ScoutSuiteAuth(flask_restful.Resource):
@jwt_required
def get(self, provider: PROVIDERS):
if provider == PROVIDERS.AWS.value:
is_setup, message = is_cloud_authentication_setup(provider)
return {'is_setup': is_setup, 'message': message}
else:
return {'is_setup': False, 'message': ''}
@jwt_required
def post(self, provider: PROVIDERS):
key_info = json.loads(request.data)
error_msg = ''
if provider == PROVIDERS.AWS.value:
try:
set_aws_keys(access_key_id=key_info['accessKeyId'],
secret_access_key=key_info['secretAccessKey'],
session_token=key_info['sessionToken'])
except InvalidAWSKeys as e:
error_msg = str(e)
return {'error_msg': error_msg}

View File

@ -69,7 +69,7 @@ class LoginPageComponent extends React.Component {
<Form className={'auth-form'} onSubmit={this.login}> <Form className={'auth-form'} onSubmit={this.login}>
<Form.Control onChange={evt => this.updateUsername(evt)} type='text' placeholder='Username'/> <Form.Control onChange={evt => this.updateUsername(evt)} type='text' placeholder='Username'/>
<Form.Control onChange={evt => this.updatePassword(evt)} type='password' placeholder='Password'/> <Form.Control onChange={evt => this.updatePassword(evt)} type='password' placeholder='Password'/>
<Button id={'auth-button'} type={'submit'}> <Button className={'monkey-submit-button'} type={'submit'}>
Login Login
</Button> </Button>
{ {

View File

@ -92,7 +92,7 @@ class RegisterPageComponent extends React.Component {
<Form className={'auth-form'} onSubmit={this.register} > <Form className={'auth-form'} onSubmit={this.register} >
<Form.Control onChange={evt => this.updateUsername(evt)} type='text' placeholder='Username'/> <Form.Control onChange={evt => this.updateUsername(evt)} type='text' placeholder='Username'/>
<Form.Control onChange={evt => this.updatePassword(evt)} type='password' placeholder='Password'/> <Form.Control onChange={evt => this.updatePassword(evt)} type='password' placeholder='Password'/>
<Button id={'auth-button'} type={'submit'} > <Button className={'monkey-submit-button'} type={'submit'} >
Let's go! Let's go!
</Button> </Button>
<Row> <Row>

View File

@ -7,7 +7,6 @@ import InlineSelection from '../../ui-components/inline-selection/InlineSelectio
import {cloneDeep} from 'lodash'; import {cloneDeep} from 'lodash';
import {faCloud, faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons'; import {faCloud, faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons';
import RunOnIslandButton from './RunOnIslandButton'; import RunOnIslandButton from './RunOnIslandButton';
import AWSSetup from './scoutsuite-setup/AWSSetup';
import CloudOptions from './scoutsuite-setup/CloudOptions'; import CloudOptions from './scoutsuite-setup/CloudOptions';
function RunOptions(props) { function RunOptions(props) {

View File

@ -1,16 +1,17 @@
import {Button} from 'react-bootstrap'; import {Button} from 'react-bootstrap';
import React from 'react'; import React from 'react';
import InlineSelection from '../../../ui-components/inline-selection/InlineSelection'; import InlineSelection from '../../../../ui-components/inline-selection/InlineSelection';
import CloudOptions from './CloudOptions'; import {COLUMN_SIZES} from '../../../../ui-components/inline-selection/utils';
import {COLUMN_SIZES} from '../../../ui-components/inline-selection/utils'; import '../../../../../styles/components/scoutsuite/AWSSetup.scss';
import '../../../../styles/components/scoutsuite/AWSSetup.scss'; import AWSSetupOptions from './AWSSetupOptions';
export default function AWSSetup(props) {
export default function AWSCLISetup(props) {
return InlineSelection(getContents, { return InlineSelection(getContents, {
...props, ...props,
collumnSize: COLUMN_SIZES.LARGE, collumnSize: COLUMN_SIZES.LARGE,
onBackButtonClick: () => { onBackButtonClick: () => {
props.setComponent(CloudOptions, props) props.setComponent(AWSSetupOptions, props);
} }
}) })
} }
@ -33,9 +34,11 @@ const getContents = (props) => {
<li> <li>
2. Run <code>aws configure</code>. It's important to configure credentials, which 2. Run <code>aws configure</code>. It's important to configure credentials, which
allows ScoutSuite to get information about your cloud configuration. The most trivial way to do so is to allows ScoutSuite to get information about your cloud configuration. The most trivial way to do so is to
provide <Button provide
<Button
href={'https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds'} href={'https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds'}
variant={'link'}> variant={'link'}
target={'_blank'}>
Access key ID and secret access key Access key ID and secret access key
</Button>. </Button>.
</li> </li>

View File

@ -0,0 +1,176 @@
import React, {useEffect, useState} from 'react';
import InlineSelection from '../../../../ui-components/inline-selection/InlineSelection';
import {COLUMN_SIZES} from '../../../../ui-components/inline-selection/utils';
import AWSSetupOptions from './AWSSetupOptions';
import {Button, Col, Form, Row} from 'react-bootstrap';
import AuthComponent from '../../../../AuthComponent';
import '../../../../../styles/components/scoutsuite/AWSSetup.scss';
import {PROVIDERS} from '../ProvidersEnum';
import classNames from 'classnames';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown';
import {faChevronUp} from '@fortawesome/free-solid-svg-icons/faChevronUp';
import {faQuestion} from '@fortawesome/free-solid-svg-icons';
import Collapse from '@kunukn/react-collapse/dist/Collapse.umd';
import keySetupForAnyUserImage from '../../../../../images/aws_keys_tutorial-any-user.png';
import keySetupForCurrentUserImage from '../../../../../images/aws_keys_tutorial-current-user.png';
import ImageModal from '../../../../ui-components/ImageModal';
export default function AWSCLISetup(props) {
return InlineSelection(getContents, {
...props,
collumnSize: COLUMN_SIZES.LARGE,
onBackButtonClick: () => {
props.setComponent(AWSSetupOptions, props);
}
})
}
const authComponent = new AuthComponent({})
const getContents = (props) => {
const [accessKeyId, setAccessKeyId] = useState('');
const [secretAccessKey, setSecretAccessKey] = useState('');
const [sessionToken, setSessionToken] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [successMessage, setSuccessMessage] = useState('');
const [docCollapseOpen, setDocCollapseOpen] = useState(false);
function submitKeys(event) {
event.preventDefault();
setSuccessMessage('');
setErrorMessage('');
authComponent.authFetch(
'/api/scoutsuite_auth/' + PROVIDERS.AWS,
{
'method': 'POST',
'body': JSON.stringify({
'accessKeyId': accessKeyId,
'secretAccessKey': secretAccessKey,
'sessionToken': sessionToken
})
})
.then(res => res.json())
.then(res => {
if (res['error_msg'] === '') {
setSuccessMessage('AWS keys saved!');
} else {
setErrorMessage(res['error_msg']);
}
});
}
useEffect(() => {
authComponent.authFetch('/api/aws_keys')
.then(res => res.json())
.then(res => {
setAccessKeyId(res['access_key_id']);
setSecretAccessKey(res['secret_access_key']);
setSessionToken(res['session_token']);
});
}, [props]);
// TODO separate into standalone component
function getKeyCreationDocsContent() {
return (
<div className={'key-creation-tutorial'}>
<h5>Tips</h5>
<p>Consider creating a new user account just for this activity. Assign only <b>ReadOnlyAccess</b> and&nbsp;
<b>SecurityAudit</b> policies.</p>
<h5>Keys for custom user</h5>
<p>1. Open the IAM console at <a href={'https://console.aws.amazon.com/iam/'}
target={'_blank'}>https://console.aws.amazon.com/iam/</a> .</p>
<p>2. In the navigation pane, choose Users.</p>
<p>3. Choose the name of the user whose access keys you want to create, and then choose the Security credentials
tab.</p>
<p>4. In the Access keys section, choose Create access key.</p>
<p>To view the new access key pair, choose Show. Your credentials will look something like this:</p>
<p>Access key ID: AKIAIOSFODNN7EXAMPLE</p>
<p>Secret access key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY</p>
<Row>
<Col lg={3} md={3} sm={5} xs={12}>
<ImageModal image={keySetupForAnyUserImage}/>
</Col>
</Row>
<h5>Keys for current user</h5>
<p>1. Click on your username in the upper right corner.</p>
<p>2. Click on "My security credentials".</p>
<p>3. In the Access keys section, choose Create access key.</p>
<p>To view the new access key pair, choose Show. Your credentials will look something like this:</p>
<p>Access key ID: AKIAIOSFODNN7EXAMPLE</p>
<p>Secret access key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY</p>
<Row>
<Col lg={3} md={3} sm={5} xs={12}>
<ImageModal image={keySetupForCurrentUserImage}/>
</Col>
</Row>
</div>);
}
function getKeyCreationDocs() {
return (
<div className={classNames('collapse-item', {'item--active': docCollapseOpen})}>
<button className={'btn-collapse'}
onClick={() => setDocCollapseOpen(!docCollapseOpen)}>
<span>
<FontAwesomeIcon icon={faQuestion} className={'question-icon'}/>
<p>How to generate keys</p>
</span>
<span>
<FontAwesomeIcon icon={docCollapseOpen ? faChevronDown : faChevronUp}/>
</span>
</button>
<Collapse
className='collapse-comp'
isOpen={docCollapseOpen}
render={getKeyCreationDocsContent}/>
</div>);
}
return (
<div className={'aws-scoutsuite-key-configuration'}>
{getKeyCreationDocs()}
<Form className={'auth-form'} onSubmit={submitKeys}>
<Form.Control onChange={evt => setAccessKeyId(evt.target.value)}
type='text'
placeholder='Access key ID'
value={accessKeyId}/>
<Form.Control onChange={evt => setSecretAccessKey(evt.target.value)}
type='password'
placeholder='Secret access key'
value={secretAccessKey}/>
<Form.Control onChange={evt => setSessionToken(evt.target.value)}
type='text'
placeholder='Session token (optional, only for temp. keys)'
value={sessionToken}/>
{
errorMessage ?
<div className="alert alert-danger" role="alert">{errorMessage}</div>
:
''
}
{
successMessage ?
<div className="alert alert-success" role="alert">{successMessage}&nbsp;
Go back and&nbsp;
<Button variant={'link'} onClick={() => props.setComponent()} className={'link-in-success-message'}>
run Monkey from the Island server </Button> to start AWS scan!</div>
:
''
}
<Row className={'justify-content-center'}>
<Col lg={4} md={6} sm={8} xs={12}>
<Button className={'monkey-submit-button'} type={'submit'}>
Submit
</Button>
</Col>
</Row>
</Form>
</div>
);
}

View File

@ -0,0 +1,40 @@
import React from 'react';
import InlineSelection from '../../../../ui-components/inline-selection/InlineSelection';
import NextSelectionButton from '../../../../ui-components/inline-selection/NextSelectionButton';
import {faKey, faTerminal} from '@fortawesome/free-solid-svg-icons';
import AWSCLISetup from './AWSCLISetup';
import CloudOptions from '../CloudOptions';
import AWSKeySetup from './AWSKeySetup';
const AWSSetupOptions = (props) => {
return InlineSelection(getContents, {
...props,
onBackButtonClick: () => {
props.setComponent(CloudOptions, props);
}
})
}
const getContents = (props) => {
return (
<>
<NextSelectionButton title={'Security keys'}
description={'Provide security keys for monkey to authenticate.'}
icon={faKey}
onButtonClick={() => {
props.setComponent(AWSKeySetup,
{setComponent: props.setComponent})
}}/>
<NextSelectionButton title={'AWS CLI'}
description={'Manually configure AWS CLI yourself.'}
icon={faTerminal}
onButtonClick={() => {
props.setComponent(AWSCLISetup,
{setComponent: props.setComponent})
}}/>
</>
)
}
export default AWSSetupOptions;

View File

@ -1,8 +1,10 @@
import React from 'react'; import React, {useEffect, useState} from 'react';
import InlineSelection from '../../../ui-components/inline-selection/InlineSelection'; import InlineSelection from '../../../ui-components/inline-selection/InlineSelection';
import NextSelectionButton from '../../../ui-components/inline-selection/NextSelectionButton'; import NextSelectionButton from '../../../ui-components/inline-selection/NextSelectionButton';
import {faCloud} from '@fortawesome/free-solid-svg-icons'; import {faCheck, faCloud, faSync} from '@fortawesome/free-solid-svg-icons';
import AWSSetup from './AWSSetup'; import AWSSetupOptions from './AWSConfiguration/AWSSetupOptions';
import {PROVIDERS} from './ProvidersEnum';
import AuthComponent from '../../../AuthComponent';
const CloudOptions = (props) => { const CloudOptions = (props) => {
@ -14,14 +16,38 @@ const CloudOptions = (props) => {
}) })
} }
const authComponent = new AuthComponent({})
const getContents = (props) => { const getContents = (props) => {
const [description, setDescription] = useState("Loading...");
const [iconType, setIconType] = useState('spinning-icon');
const [icon, setIcon] = useState(faSync);
useEffect(() => {
authComponent.authFetch('/api/scoutsuite_auth/' + PROVIDERS.AWS)
.then(res => res.json())
.then(res => {
if(res.is_setup){
setDescription(res.message + 'Click next to change the configuration.');
setIconType('icon-success');
setIcon(faCheck);
} else {
setDescription('Setup Amazon Web Services infrastructure scan.');
setIconType('')
setIcon(faCloud);
}
});
}, [props]);
return ( return (
<> <>
<NextSelectionButton title={'AWS'} <NextSelectionButton title={'AWS'}
description={'Setup Amazon Web Services infrastructure scan.'} description={description}
icon={faCloud} icon={icon}
iconType={iconType}
onButtonClick={() => { onButtonClick={() => {
props.setComponent(AWSSetup, props.setComponent(AWSSetupOptions,
{setComponent: props.setComponent}) {setComponent: props.setComponent})
}}/> }}/>
</> </>

View File

@ -0,0 +1,33 @@
import React, {useState} from 'react';
import PropTypes from 'prop-types';
import {Button, Image, Modal} from 'react-bootstrap';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faSearchPlus} from '@fortawesome/free-solid-svg-icons';
const ImageModal = (props) => {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div className={'image-modal'}>
<Button className={'image-modal-thumbnail'} onClick={() => setIsModalOpen(true)}>
<FontAwesomeIcon icon={faSearchPlus} className={'image-modal-thumbnail-icon'}/>
<Image src={props.image} thumbnail fluid/>
</Button>
<Modal show={isModalOpen}
className={'image-modal-screen'}
onHide={() => setIsModalOpen(false)}>
<Modal.Body>
<Image src={props.image} fluid />
</Modal.Body>
</Modal>
</div>
);
}
export default ImageModal;
ImageModal.propTypes = {
image: PropTypes.element
}

View File

@ -18,8 +18,8 @@ export default function InlineSelection(WrappedComponent, props) {
) )
} }
function renderBackButton(props){ function renderBackButton(props) {
if(props.onBackButtonClick !== undefined){ if (props.onBackButtonClick !== undefined) {
return (<BackButton onClick={props.onBackButtonClick}/>); return (<BackButton onClick={props.onBackButtonClick}/>);
} }
} }

View File

@ -6,7 +6,8 @@ import {faAngleRight} from '@fortawesome/free-solid-svg-icons';
export default function nextSelectionButton(props) { export default function nextSelectionButton(props) {
let description = props.description !== undefined ? (<p>{props.description}</p>) : '' let description = props.description !== undefined ? (<p>{props.description}</p>) : ''
let icon = props.icon !== undefined ? (<FontAwesomeIcon icon={props.icon}/>) : '' let iconType = props.iconType !== undefined ? props.iconType : ''
let icon = props.icon !== undefined ? (<FontAwesomeIcon className={iconType} icon={props.icon}/>) : ''
return ( return (
<Row> <Row>
<Col> <Col>
@ -24,6 +25,7 @@ export default function nextSelectionButton(props) {
nextSelectionButton.propTypes = { nextSelectionButton.propTypes = {
title: PropTypes.string, title: PropTypes.string,
iconType: PropTypes.string,
icon: FontAwesomeIcon, icon: FontAwesomeIcon,
description: PropTypes.string, description: PropTypes.string,
onButtonClick: PropTypes.func onButtonClick: PropTypes.func

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -3,6 +3,7 @@
@import '../../node_modules/bootstrap/scss/bootstrap'; @import '../../node_modules/bootstrap/scss/bootstrap';
// Imports that require variables // Imports that require variables
@import 'components/Buttons';
@import 'pages/report/ReportPage.scss'; @import 'pages/report/ReportPage.scss';
@import 'pages/report/AttackReport.scss'; @import 'pages/report/AttackReport.scss';
@import 'pages/ConfigurationPage'; @import 'pages/ConfigurationPage';
@ -13,11 +14,12 @@
@import 'components/AdvancedMultiSelect'; @import 'components/AdvancedMultiSelect';
@import 'components/particle-component/ParticleBackground'; @import 'components/particle-component/ParticleBackground';
@import 'components/scoutsuite/ResourceDropdown'; @import 'components/scoutsuite/ResourceDropdown';
@import 'components/ImageModal';
@import 'components/Icons';
@import 'components/inline-selection/InlineSelection'; @import 'components/inline-selection/InlineSelection';
@import 'components/inline-selection/NextSelectionButton'; @import 'components/inline-selection/NextSelectionButton';
@import 'components/inline-selection/BackButton'; @import 'components/inline-selection/BackButton';
@import 'components/inline-selection/CommandDisplay'; @import 'components/inline-selection/CommandDisplay';
@import 'components/Icons';
// Define custom elements after bootstrap import // Define custom elements after bootstrap import

View File

@ -3,6 +3,14 @@
display: inline-block; display: inline-block;
} }
.icon-success {
color: $success
}
.icon-failed {
color: $danger;
}
@keyframes spin-animation { @keyframes spin-animation {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);

View File

@ -0,0 +1,49 @@
.image-modal .image-modal-thumbnail {
position: relative;
padding: 7px;
}
.image-modal .image-modal-thumbnail:focus {
background-color: white;
border-color: white;
box-shadow: 0 2px 6px #ccc;
}
.image-modal .image-modal-thumbnail:hover {
background-color: white;
border-color: white;
box-shadow: 0 2px 6px #ccc;
}
.image-modal .image-modal-thumbnail-icon {
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
position: absolute;
min-width: 40px;
min-height: 40px;
}
.image-modal:hover .image-modal-thumbnail-icon {
color: $monkey-yellow;
}
.image-modal-screen {
padding: 0;
}
.image-modal-screen .modal-dialog {
margin: 0;
top: 0;
width: 100%;
padding: 30px;
max-width: none;
max-height: none;
}
.image-modal-screen .modal-dialog .modal-content {
width: fit-content;
margin: auto;
}

View File

@ -1,17 +1,74 @@
.aws-scoutsuite-configuration a{ .aws-scoutsuite-configuration a {
display: inline-block; display: inline-block;
padding: 0 0 3px 0; padding: 0 0 3px 0;
} }
.aws-scoutsuite-configuration ol{ .aws-scoutsuite-configuration ol {
padding-left: 15px; padding-left: 15px;
margin-bottom: 30px; margin-bottom: 30px;
} }
.aws-scoutsuite-configuration ol.nested-ol{ .aws-scoutsuite-configuration ol.nested-ol {
margin-bottom: 0; margin-bottom: 0;
} }
.aws-scoutsuite-configuration li{ .aws-scoutsuite-configuration li {
margin-bottom: 5px; margin-bottom: 5px;
} }
.monkey-submit-button {
margin-bottom: 15px;
}
.aws-scoutsuite-key-configuration .collapse-item {
padding: 0;
margin-bottom: 15px;
}
.aws-scoutsuite-key-configuration .collapse-item .btn-collapse .question-icon {
display: inline-block;
margin-right: 7px;
margin-bottom: 1px;
}
.aws-scoutsuite-key-configuration .collapse-item .btn-collapse p {
display: inline-block;
margin-bottom: 0;
font-size: 1.2em;
margin-left: 5px
}
.aws-scoutsuite-key-configuration .key-creation-tutorial {
padding-bottom: 10px;
}
.aws-scoutsuite-key-configuration .key-creation-tutorial p {
margin-bottom: 2px;
font-weight: 400;
}
.aws-scoutsuite-key-configuration .key-creation-tutorial h5 {
margin-top: 15px;
font-weight: 600;
}
.aws-scoutsuite-key-configuration .key-creation-tutorial p:first-child {
margin-top: 15px;
}
.aws-scoutsuite-key-configuration .image-modal {
margin-top: 5px;
}
.aws-scoutsuite-key-configuration .key-creation-tutorial img {
max-width: 100%;
max-height: 100%;
border: 1px solid black;
}
.link-in-success-message {
padding: 0 !important;
vertical-align: initial !important;
}

View File

@ -15,23 +15,6 @@
margin-top: 20px; margin-top: 20px;
} }
#auth-button {
border-color: #3f3f3f;
font-size: 1.3em;
width: 100%;
background-color: #3f3f3f;
color: $monkey-yellow;
}
#auth-button:hover {
border-color: $monkey-yellow;
font-size: 1.3em;
font-weight: bold;
width: 100%;
background-color: $monkey-yellow;
color: #000000;
}
.monkey-detective { .monkey-detective {
max-height: 500px; max-height: 500px;
} }