Discussion:
[systemd-devel] transforming Iptables bash script to systemd service file -help
lux-integ
2014-09-12 08:57:14 UTC
Permalink
Greetings,

I am attempting to learn to use systemd. I have an IPtbales script I intend
to transform from a bash script to a systemd service file.

It has lines such as
iptables -A INPUt -p tcp ......-j ACCEPT
which I intend to transform to
ExecStart=iptables -A INPUT -p tcp ......-j ACCEPT

however it has 'conditionally-processed lines like these
if [ something=1 ];
iptables -A INPUT -p tcp ......-j ACCEPT
fi

where $something is an environmental variable set in an external file.

I read hrough the systemd manual page on unit files
( http://www.freedesktop.org/software/systemd/man/systemd.unit.html )
and the closet match I see is the use of two lines
ConditionFileNotEmpty=SomeFile
ConditionNull=0
where I presume one could create 'SomefFile' with something in it to trigger
a logical 0 so avoiding processing the service file.
If I am not wong this would only relate to the processing of a service file
that that THIS unit file relates to.

And this would conflict with my requirement as I want ONE largish IPtables
service file.

The question is; is there a way of conditionally procesing lines in systemd
service files such as the following

ExecStart=/path/to/executible1
ExecStart=/path/to/executible2
some condition satisfied ( for example ConditionFileNotEmpty=SomeFile .....
)
ExecStart=/path/to/executible3
..back to 'unconditional processing
ExecStart=/path/to/executible4


I also read through the service file manual-page
( http://www.freedesktop.org/software/systemd/man/systemd.service.html )


and I am wondering if
ExecStartPre= and ExecStartPost=
could be used and if so how so

Advice will be appreciated
sincerely
luxInteg
Zbigniew Jędrzejewski-Szmek
2014-09-12 09:59:50 UTC
Permalink
Hi,
this approach doesn't make much sense, for a few reasons.

First, having systemd execute each line as a separate command
is not very efficient: systemd is doing other things at the same
time, and will interleave other jobs with the commands, log lots
of things, etc.

Second, embedding such conditionals in the unit file is always
going to be very awkward for editing and updating.

Third, most important probably, is that you really want iptables'
rules to be loaded atomically. Using iptables-restore gives you
such atomicity and is much better.

IMHO, you should use this approach, ie. somehow construct the set
of rules and load it all at once.

Zbyszek
Simon McVittie
2014-09-12 10:53:23 UTC
Permalink
Post by lux-integ
The question is; is there a way of conditionally procesing lines in systemd
service files such as the following
ExecStart=/path/to/executible1
ExecStart=/path/to/executible2
some condition satisfied ( for example ConditionFileNotEmpty=SomeFile .....
)
ExecStart=/path/to/executible3
..back to 'unconditional processing
ExecStart=/path/to/executible4
The way to do this is to write a script in the programming language of
your choice (bash is one possibility), and have the systemd service file
run that. There would be little point in systemd reinventing a generic
script interpreter: we already have lots of those (bash, Python, etc.)

For the specific case of iptables, "what Zbigniew said": it would be
better for your script to compose a file or buffer in
iptables-save/iptables-restore syntax, and pipe it to iptables-restore,
so that it can be applied atomically.

S
lux-integ
2014-09-12 12:04:40 UTC
Permalink
Post by Simon McVittie
The way to do this is to write a script in the programming language of
your choice (bash is one possibility), and have the systemd service file
run that. There would be little point in systemd reinventing a generic
script interpreter: we already have lots of those (bash, Python, etc.)
thanks to you and others
I only ask as I was under the impression that bash scripting was a no-no for
systemd implementations


I will stick with the tried and tested bash scripts for iptables
then try something like

ExecStart=/bin/sh -c " path/to/IptablesScript"

inside a servce file

will this suffce ?
Reindl Harald
2014-09-12 12:20:01 UTC
Permalink
Post by lux-integ
Post by Simon McVittie
The way to do this is to write a script in the programming language of
your choice (bash is one possibility), and have the systemd service file
run that. There would be little point in systemd reinventing a generic
script interpreter: we already have lots of those (bash, Python, etc.)
thanks to you and others
I only ask as I was under the impression that bash scripting was a no-no for
systemd implementations
I will stick with the tried and tested bash scripts for iptables
then try something like
ExecStart=/bin/sh -c " path/to/IptablesScript"
inside a servce file
will this suffce ?
why want you do that?

on Redhat systems end your script with "/usr/sbin/iptables-save > /etc/sysconfig/iptables"
and just enable the iptables service, the pre-generated rules will be loaded at boot from
iptables - there is really no need to fire up the shell script each boot

i maintain around 30 servers that way with a distributed "iptables.sh"
which has general rules and some depending on $HOSTNAME for many years
Lennart Poettering
2014-10-21 19:30:23 UTC
Permalink
Post by lux-integ
Post by Simon McVittie
The way to do this is to write a script in the programming language of
your choice (bash is one possibility), and have the systemd service file
run that. There would be little point in systemd reinventing a generic
script interpreter: we already have lots of those (bash, Python, etc.)
thanks to you and others
I only ask as I was under the impression that bash scripting was a no-no for
systemd implementations
To make this clear: while be deemphasize the use of shell in the boot
process by no means it's forbidden. Absolutely not.

If you need a shell, use a shell, systemd's unit files are explicitly
not one, and shall not replace one.

For most services a shell is pretty unnecessary, and in those cases it
is great to get rid of it. But in cases like the iptables tool (which
is written in a style that kinda requires the usage of shell scripts
to invoke it, since it is more a programming language and is seldom
called just once at boot), do make use them.

Lennart
--
Lennart Poettering, Red Hat
Simon McVittie
2014-10-22 11:37:36 UTC
Permalink
Post by Lennart Poettering
But in cases like the iptables tool (which
is written in a style that kinda requires the usage of shell scripts
to invoke it, since it is more a programming language and is seldom
called just once at boot)
If your ruleset is static (e.g. does not depend on the local IP
address), it's very close to not needing a shell: all it would need is
for systemd to support StandardInput=/a/file/path, or for
iptables-restore to support "--file /a/file/path", or something similar.

iptables-save | sudo tee /etc/my-firewall
ip6tables-save | sudo tee /etc/my-firewall6

ExecStart=/bin/sh -c 'iptables-restore < /etc/my-firewall'

ExecStart=/bin/sh -c 'ip6tables-restore < /etc/my-firewall6'

S
Alexandre Detiste
2014-10-23 07:17:10 UTC
Permalink
all it would need is for systemd to support StandardInput=/a/file/path
That feature would be nice.
I have a direct use for this.
Doing '/bin/echo -e line1\\nline2\\nline3 | command' is ugly.

https://github.com/systemd-cron/systemd-cron/blob/master/src/bin/systemd-crontab-generator#L229
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html
Jóhann B. Guðmundsson
2014-10-23 07:36:59 UTC
Permalink
Post by Alexandre Detiste
all it would need is for systemd to support StandardInput=/a/file/path
That feature would be nice.
I have a direct use for this.
Doing '/bin/echo -e line1\\nline2\\nline3 | command' is ugly.
Not really the general idea is and always has been having people calling
Exec*=/path/to/my-script instead which contains commandline $foo and a
proper exit code not for people to have oneliner contests in those Exec*
lines

JBG
Lennart Poettering
2014-10-23 09:44:42 UTC
Permalink
Post by Alexandre Detiste
all it would need is for systemd to support StandardInput=/a/file/path
That feature would be nice.
I have a direct use for this.
Doing '/bin/echo -e line1\\nline2\\nline3 | command' is ugly.
https://github.com/systemd-cron/systemd-cron/blob/master/src/bin/systemd-crontab-generator#L229
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html
People have also requested StandardOutput=/some/file. That's something
though I really don't want to support, since it leaves the question of
rotation open.

I guess I'd be willing to merge a patch that adds this for
StandardInput= however. It appears OK to me.

Lennart
--
Lennart Poettering, Red Hat
Dave Reisner
2014-10-23 12:18:46 UTC
Permalink
Post by Simon McVittie
Post by Lennart Poettering
But in cases like the iptables tool (which
is written in a style that kinda requires the usage of shell scripts
to invoke it, since it is more a programming language and is seldom
called just once at boot)
If your ruleset is static (e.g. does not depend on the local IP
address), it's very close to not needing a shell: all it would need is
for systemd to support StandardInput=/a/file/path, or for
iptables-restore to support "--file /a/file/path", or something similar.
iptables-save | sudo tee /etc/my-firewall
ip6tables-save | sudo tee /etc/my-firewall6
ExecStart=/bin/sh -c 'iptables-restore < /etc/my-firewall'
ExecStart=/bin/sh -c 'ip6tables-restore < /etc/my-firewall6'
While it isn't documented in the manpage, the iptables-restore code
documents that if a single non-option argument is passed, it will try to
use that as the rule source to restore:

if (optind == argc - 1) {
in = fopen(argv[optind], "re");
if (!in) {
fprintf(stderr, "Can't open %s: %s\n", argv[optind],
strerror(errno));
exit(1);
}
}
else if (optind < argc) {
fprintf(stderr, "Unknown arguments found on commandline\n");
exit(1);
}
else in = stdin;

So, no need for any redirects here. Arch ships this for an iptables
service:

[Unit]
Description=Packet Filtering Framework

[Service]
Type=oneshot
ExecStart=/usr/bin/iptables-restore /etc/iptables/iptables.rules
ExecReload=/usr/bin/iptables-restore /etc/iptables/iptables.rules
ExecStop=/usr/lib/systemd/scripts/iptables-flush
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Cheers,
Dr
Lennart Poettering
2014-10-21 19:31:25 UTC
Permalink
Post by lux-integ
I will stick with the tried and tested bash scripts for iptables
then try something like
ExecStart=/bin/sh -c " path/to/IptablesScript"
inside a servce file
will this suffce ?
Yes. However, the "/bin/sh -c" thing is unnecessary. Just set the +x
bit on the script, add the she-bang to the first line and call it
directly.

Lennart
--
Lennart Poettering, Red Hat
Jóhann B. Guðmundsson
2014-09-12 12:36:01 UTC
Permalink
Post by lux-integ
Greetings,
I am attempting to learn to use systemd. I have an IPtbales script I intend
to transform from a bash script to a systemd service file.
If it had been technically possible to migrate the legacy sysv
initscript to native systemd we ( as in me and Thomas Woerner
<mailto:***@redhat.com> ) would have done so during the F15
development cycle ( rather then F16 I believe )but due to wide variety
of reasons most obvious one being that you loose iptables-restore and
iptables-save we did not so I suggest you start with something that
actually works.

I'm currently looking into implementing/integrating proper nftables
support into systemd which is possible now since nftables has a proper
client library to talk to the kernel.

If and then when that work completes ( based on how well it goes and my
free time ) distribution should be able to drop iptables and the legacy
sysv initscript along with it chose they to do so.

JBG
Loading...