Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FS-Azure/ContainerAppIPRestriction #2075

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,7 @@ module.exports = {
'containerAppVolumeMount' : require(__dirname + '/plugins/azure/containerapps/containerAppVolumeMount.js'),
'containerAppHttpsOnly' : require(__dirname + '/plugins/azure/containerapps/containerAppHttpsOnly.js'),
'containerAppHasTags' : require(__dirname + '/plugins/azure/containerapps/containerAppHasTags.js'),
'containerAppIPRestriction' : require(__dirname + '/plugins/azure/containerapps/containerAppIPRestriction.js'),

'workspacePublicAccessDisabled' : require(__dirname + '/plugins/azure/machinelearning/workspacePublicAccessDisabled.js'),
'workspaceLoggingEnabled' : require(__dirname + '/plugins/azure/machinelearning/workspaceLoggingEnabled.js'),
Expand Down
2 changes: 1 addition & 1 deletion plugins/aws/eks/eksKubernetesVersion.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('eksKubernetesVersion', function () {
"cluster": {
"name": "mycluster",
"arn": "arn:aws:eks:us-east-1:012345678911:cluster/mycluster",
"version": "1.27",
"version": "1.29",
}
}
);
Expand Down
61 changes: 61 additions & 0 deletions plugins/azure/containerapps/containerAppIPRestriction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
var async = require('async');
var helpers = require('../../../helpers/azure');

module.exports = {
title: 'Container Apps IP Restriction Configured',
category: 'Container Apps',
domain: 'Containers',
severity: 'Medium',
description: 'Ensures that Container Apps are configured to allow only specific IP addresses.',
more_info: 'Azure Container Apps provides IP ingress restrictions for controlling inbound traffic, enhancing application security. Allow or deny rules can be defined for specific IP ranges, enabling precise access management to container apps. This feature is crucial for reducing potential security vulnerabilities, as unrestricted configurations permit all inbound traffic by default.',
recommended_action: 'Modify Container Apps and configure IP restriction.',
link: 'https://learn.microsoft.com/en-us/azure/container-apps/ip-restrictions',
apis: ['containerApps:list'],
realtime_triggers: ['microsoftapp:containerapps:write', 'microsoftapp:containerapps:delete'],

run: function(cache, settings, callback) {
var results = [];
var source = {};
var locations = helpers.locations(settings.govcloud);

async.each(locations.containerApps, function(location, rcb) {
var containerApps = helpers.addSource(cache, source,
['containerApps', 'list', location]);

if (!containerApps) return rcb();

if (containerApps.err || !containerApps.data) {
helpers.addResult(results, 3,
'Unable to query for Container apps: ' + helpers.addError(containerApps), location);
return rcb();
}

if (!containerApps.data.length) {
helpers.addResult(results, 0, 'No existing Container apps found', location);
return rcb();
}

for (let container of containerApps.data) {
if (!container.id) continue;
alphadev4 marked this conversation as resolved.
Show resolved Hide resolved

if (container.configuration &&
container.configuration.ingress &&
container.configuration.ingress.ipSecurityRestrictions &&
container.configuration.ingress.ipSecurityRestrictions.length) {
helpers.addResult(results, 0,
'Container app has IP restrictions configured', location, container.id);

} else {
helpers.addResult(results, 2,
'Container app does not have IP restrictions configured', location, container.id);
}
}

rcb();
}, function() {
// Global checking goes here
callback(null, results, source);
});
}
};

149 changes: 149 additions & 0 deletions plugins/azure/containerapps/containerAppIPRestriction.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
var expect = require('chai').expect;
var containerAppIPRestriction = require('./containerAppIPRestriction');

const containerApps = [
{
"id": "/subscriptions/123456/resourceGroups/tesr/providers/Microsoft.App/containerapps/test1",
"name": "test1",
"type": "Microsoft.App/containerApps",
"configuration": {
"ingress": {
"fqdn": "testfatima.wittysea-8163cba4.australiaeast.azurecontainerapps.io",
"external": true,
"targetPort": 300,
"exposedPort": 0,
"transport": "Auto",
"traffic": [
{
"weight": 100,
"latestRevision": true
}
],
"customDomains": null,
"allowInsecure": false,
"ipSecurityRestrictions": [
{
"action":'Allow',
"description":'dummy',
"ipAddressRange": '00000',
"name": 'test'
}
],
"corsPolicy": null,
"clientCertificateMode": "Ignore",
"stickySessions": {
"affinity": "none"
}
},
},
"identity": {
"type": "SystemAssigned"
}

},
{
"id": "/subscriptions/123456/resourceGroups/tesr/providers/Microsoft.App/containerapps/test2",
"name": "test2",
"type": "Microsoft.App/containerApps",
"configuration": {
"ingress": {
"fqdn": "testfatima.wittysea-8163cba4.australiaeast.azurecontainerapps.io",
"external": true,
"targetPort": 300,
"exposedPort": 0,
"transport": "Auto",
"traffic": [
{
"weight": 100,
"latestRevision": true
}
],
"customDomains": null,
"allowInsecure": true,
"ipSecurityRestrictions": null,
"corsPolicy": null,
"clientCertificateMode": "Ignore",
"stickySessions": {
"affinity": "none"
}
},
},
"identity": {
"type": "None"
}
},
];



const createCache = (container) => {
return {
containerApps: {
list: {
'eastus': {
data: container
}
}
}
};
};

const createErrorCache = () => {
return {
containerApps: {
list: {
'eastus': {}
}
}
};
};

describe('containerAppIPRestriction', function() {
describe('run', function() {
it('should give passing result if no container apps', function(done) {
const cache = createCache([]);
containerAppIPRestriction.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('No existing Container apps found');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give unknown result if unable to query for container apps', function(done) {
const cache = createErrorCache();
containerAppIPRestriction.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(3);
expect(results[0].message).to.include('Unable to query for Container apps: ');
expect(results[0].region).to.equal('eastus');
done();
});
});


it('should give passing result if container app has IP restrictions configured', function(done) {
const cache = createCache([containerApps[0]]);
containerAppIPRestriction.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Container app has IP restrictions configured');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give failing result if container app does not have IP restrictions configured', function(done) {
const cache = createCache([containerApps[1]]);
containerAppIPRestriction.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Container app does not have IP restrictions configured');
expect(results[0].region).to.equal('eastus');
done();
});
});

});
});
Loading