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

Feature palo alto 11x #20236

Merged
merged 19 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions changelog/unreleased/issue-20223.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type="a"
danotorrey marked this conversation as resolved.
Show resolved Hide resolved
message="Added new Palo Alto version 11 input to ingest PAN OS 11 logs."
danotorrey marked this conversation as resolved.
Show resolved Hide resolved

issues=["20223"]
ryan-carroll-graylog marked this conversation as resolved.
Show resolved Hide resolved
pulls=["20236"]
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.graylog.integrations.dataadapters.GreyNoiseQuickIPDataAdapter;
import org.graylog.integrations.inputs.paloalto.PaloAltoCodec;
import org.graylog.integrations.inputs.paloalto.PaloAltoTCPInput;
import org.graylog.integrations.inputs.paloalto11.PaloAlto11xCodec;
import org.graylog.integrations.inputs.paloalto11.PaloAlto11xInput;
import org.graylog.integrations.inputs.paloalto9.PaloAlto9xCodec;
import org.graylog.integrations.inputs.paloalto9.PaloAlto9xInput;
import org.graylog.integrations.ipfix.codecs.IpfixCodec;
Expand Down Expand Up @@ -171,6 +173,11 @@ private void configureUniversalBindings() {
addMessageInput(PaloAlto9xInput.class);
addCodec(PaloAlto9xCodec.NAME, PaloAlto9xCodec.class);

// Palo Alto Networks 11x
LOG.debug("Registering message input: {}", PaloAlto11xInput.NAME);
addMessageInput(PaloAlto11xInput.class);
addCodec(PaloAlto11xCodec.NAME, PaloAlto11xCodec.class);

// AWS
addCodec(AWSCodec.NAME, AWSCodec.class);
addCodec(KinesisCloudWatchFlowLogCodec.NAME, KinesisCloudWatchFlowLogCodec.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.integrations.inputs.paloalto11;

import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import org.graylog.integrations.inputs.paloalto.PaloAltoMessageBase;
import org.graylog.integrations.inputs.paloalto.PaloAltoParser;
import org.graylog.schema.EventFields;
import org.graylog.schema.VendorFields;
import org.graylog2.plugin.Message;
import org.graylog2.plugin.MessageFactory;
import org.graylog2.plugin.ResolvableInetSocketAddress;
import org.graylog2.plugin.configuration.Configuration;
import org.graylog2.plugin.configuration.ConfigurationRequest;
import org.graylog2.plugin.configuration.fields.BooleanField;
import org.graylog2.plugin.configuration.fields.ConfigurationField;
import org.graylog2.plugin.configuration.fields.DropdownField;
import org.graylog2.plugin.inputs.annotations.ConfigClass;
import org.graylog2.plugin.inputs.annotations.FactoryClass;
import org.graylog2.plugin.inputs.codecs.Codec;
import org.graylog2.plugin.inputs.codecs.CodecAggregator;
import org.graylog2.plugin.journal.RawMessage;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

import static com.google.common.base.MoreObjects.firstNonNull;

public class PaloAlto11xCodec implements Codec {
private static final Logger LOG = LoggerFactory.getLogger(PaloAlto11xCodec.class);
static final String CK_STORE_FULL_MESSAGE = "store_full_message";
static final String CK_TIMEZONE = "timezone";

public static final String NAME = "PaloAlto11x";
public static final String EVENT_SOURCE_PRODUCT_NAME = "PAN";
public static final String UNKNOWN = "unknown";

private final Configuration configuration;
private final MessageFactory messageFactory;
private final PaloAltoParser rawMessageParser;
private final DateTimeZone timezone;

@AssistedInject
public PaloAlto11xCodec(@Assisted Configuration configuration, PaloAltoParser rawMessageParser,
MessageFactory messageFactory) {
this.configuration = configuration;
this.messageFactory = messageFactory;
String timezoneID = configuration.getString(CK_TIMEZONE);
// previously existing PA inputs after updating will not have a Time Zone configured, default to UTC
this.timezone = timezoneID != null ? DateTimeZone.forID(timezoneID) : DateTimeZone.UTC;
LOG.trace("Configured with time zone: {}", timezone);
this.rawMessageParser = rawMessageParser;
}

@Nullable
@Override
public Message decode(@Nonnull RawMessage rawMessage) {
String s = new String(rawMessage.getPayload(), StandardCharsets.UTF_8);
danotorrey marked this conversation as resolved.
Show resolved Hide resolved
LOG.trace("Received raw message: {}", s);

PaloAltoMessageBase p = null;
try {
p = rawMessageParser.parse(s, timezone);
} catch (Exception e) {
LOG.warn("Cannot parse malformed Palo Alto 11x Message. Leaving message unparsed: {}", s);
}

String payload = s;
String source = getRawMessageSource(rawMessage);
DateTime timestamp = DateTime.now(DateTimeZone.UTC);
String panType = UNKNOWN;
if (p != null) {
payload = firstNonNull(p.payload(), payload);
source = firstNonNull(p.source(), source);
timestamp = firstNonNull(p.timestamp(), DateTime.now(DateTimeZone.UTC));
panType = firstNonNull(p.panType(), UNKNOWN);
}
danotorrey marked this conversation as resolved.
Show resolved Hide resolved

Message message = messageFactory.createMessage(payload, source, timestamp);
message.addField(EventFields.EVENT_SOURCE_PRODUCT, EVENT_SOURCE_PRODUCT_NAME);
message.addField(VendorFields.VENDOR_SUBTYPE, panType);
// Store full message if configured.
if (configuration.getBoolean(CK_STORE_FULL_MESSAGE)) {
message.addField(Message.FIELD_FULL_MESSAGE, new String(rawMessage.getPayload(), StandardCharsets.UTF_8));
}
LOG.trace("Successfully processed [{}] message with [{}] fields.", panType, message.getFieldCount());
return message;
}

private String getRawMessageSource(RawMessage rawMessage) {
final ResolvableInetSocketAddress address = rawMessage.getRemoteAddress();
final InetSocketAddress remoteAddress;
if (address == null) {
remoteAddress = null;
} else {
remoteAddress = address.getInetSocketAddress();
}

return remoteAddress == null ? UNKNOWN: remoteAddress.getAddress().toString();
danotorrey marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public String getName() {
return NAME;
}

@Nonnull
@Override
public Configuration getConfiguration() {
return this.configuration;
}

@FactoryClass
public interface Factory extends Codec.Factory<PaloAlto11xCodec> {
@Override
PaloAlto11xCodec create(Configuration configuration);

@Override
PaloAlto11xCodec.Config getConfig();
}

@ConfigClass
public static class Config implements Codec.Config {
@Override
public ConfigurationRequest getRequestedConfiguration() {
final ConfigurationRequest r = new ConfigurationRequest();

r.addField(new DropdownField(
CK_TIMEZONE,
"Time Zone",
DateTimeZone.UTC.getID(),
DropdownField.ValueTemplates.timeZones(),
"Time zone of the Palo Alto device",
ConfigurationField.Optional.OPTIONAL));

r.addField(
new BooleanField(
CK_STORE_FULL_MESSAGE,
"Store full message?",
false,
"Store the full original Palo Alto message as full_message?"
)
);

return r;
}

@Override
public void overrideDefaultValues(@Nonnull ConfigurationRequest cr) {
}
}

@Nullable
@Override
public CodecAggregator getAggregator() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.integrations.inputs.paloalto11;

import com.codahale.metrics.MetricRegistry;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import org.graylog2.inputs.transports.SyslogTcpTransport;
import org.graylog2.plugin.LocalMetricRegistry;
import org.graylog2.plugin.ServerStatus;
import org.graylog2.plugin.configuration.Configuration;
import org.graylog2.plugin.inputs.MessageInput;
import org.graylog2.plugin.inputs.annotations.ConfigClass;
import org.graylog2.plugin.inputs.annotations.FactoryClass;

public class PaloAlto11xInput extends MessageInput {

public static final String NAME = "Palo Alto Networks TCP (PAN-OS v11+)";

@Inject
public PaloAlto11xInput(@Assisted Configuration configuration,
MetricRegistry metricRegistry,
SyslogTcpTransport.Factory transport,
LocalMetricRegistry localRegistry,
PaloAlto11xCodec.Factory codec,
PaloAlto11xInput.Config config,
PaloAlto11xInput.Descriptor descriptor,
ServerStatus serverStatus) {
super(
metricRegistry,
configuration,
transport.create(configuration),
localRegistry,
codec.create(configuration),
config,
descriptor,
serverStatus);
}

@FactoryClass
public interface Factory extends MessageInput.Factory<PaloAlto11xInput> {
@Override
PaloAlto11xInput create(Configuration configuration);

@Override
PaloAlto11xInput.Config getConfig();

@Override
PaloAlto11xInput.Descriptor getDescriptor();
}

public static class Descriptor extends MessageInput.Descriptor {
public Descriptor() {
super(NAME, false, "");
}
}

@ConfigClass
public static class Config extends MessageInput.Config {

@Inject
public Config(SyslogTcpTransport.Factory transport, PaloAlto11xCodec.Factory codec) {
super(transport.getConfig(), codec.getConfig());
}
}
}
Loading
Loading